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>
17 #include <afs/pthread_glock.h>
18 #include <sys/types.h>
25 #include <netinet/in.h>
30 #include <stdlib.h> /* for realpath() */
37 #include <rx/rx_identity.h>
39 #include <afs/afsutil.h>
40 #include <afs/fileutil.h>
42 #ifdef AFS_ATHENA_STDENV
47 #include "cellconfig.h"
49 #include "afs/audit.h"
51 /* The display names for localauth and noauth identities; they aren't used
52 * inside tickets or anything, but just serve as something to display in logs,
54 #define AFS_LOCALAUTH_NAME "<LocalAuth>"
55 #define AFS_LOCALAUTH_LEN (sizeof(AFS_LOCALAUTH_NAME)-1)
56 #define AFS_NOAUTH_NAME "<NoAuth>"
57 #define AFS_NOAUTH_LEN (sizeof(AFS_NOAUTH_NAME)-1)
59 static int ParseLine(char *buffer, struct rx_identity *user);
62 UserListFileName(struct afsconf_dir *adir,
63 char *buffer, size_t len)
65 strcompose(buffer, len, adir->name, "/",
66 AFSDIR_ULIST_FILE, NULL);
71 afsconf_CheckAuth(void *arock, struct rx_call *acall)
73 struct afsconf_dir *adir = (struct afsconf_dir *) arock;
76 rc = ((afsconf_SuperUser(adir, acall, NULL) == 0) ? 10029 : 0);
80 #endif /* !defined(UKERNEL) */
83 GetNoAuthFlag(struct afsconf_dir *adir)
85 if (access(AFSDIR_SERVER_NOAUTH_FILEPATH, 0) == 0) {
86 osi_audit(NoAuthEvent, 0, AUD_END); /* some random server is running noauth */
87 return 1; /* if /usr/afs/local/NoAuth file exists, allow access */
94 afsconf_GetNoAuthFlag(struct afsconf_dir *adir)
99 rc = GetNoAuthFlag(adir);
105 afsconf_SetNoAuthFlag(struct afsconf_dir *adir, int aflag)
111 /* turn off noauth flag */
112 code = (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH) ? errno : 0);
113 osi_audit(NoAuthDisableEvent, code, AUD_END);
115 /* try to create file */
117 open(AFSDIR_SERVER_NOAUTH_FILEPATH, O_CREAT | O_TRUNC | O_RDWR,
121 osi_audit(NoAuthEnableEvent, 0, AUD_END);
123 osi_audit(NoAuthEnableEvent, errno, AUD_END);
129 * Remove an identity from the UserList file
131 * This function removes the given identity from the user list file.
132 * For the purposes of identifying entries to remove, only the
133 * type and exportedName portions of the identity are used. Callers
134 * should remember that a given identity may be listed in the file in
135 * a number of different ways.
138 * A structure representing the configuration directory currently
141 * The RX identity to delete
144 * 0 on success, an error code on failure
148 afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
159 struct rx_identity identity;
162 memset(&identity, 0, sizeof(struct rx_identity));
165 UserListFileName(adir, tbuffer, sizeof tbuffer);
169 * We attempt to fully resolve this pathname, so that the rename
170 * of the temporary file will work even if UserList is a symlink
171 * into a different filesystem.
173 char resolved_path[1024];
175 if (realpath(tbuffer, resolved_path)) {
176 strcpy(tbuffer, resolved_path);
179 #endif /* AFS_NT40_ENV */
180 tf = fopen(tbuffer, "r");
185 code = stat(tbuffer, &tstat);
190 strcpy(nbuffer, tbuffer);
191 strcat(nbuffer, ".NXX");
192 nf = fopen(nbuffer, "w+");
201 /* check for our user id */
202 tp = fgets(nbuffer, sizeof(nbuffer), tf);
206 copy = strdup(nbuffer);
211 code = ParseLine(copy, &identity);
212 if (code == 0 && rx_identity_match(user, &identity)) {
213 /* found the guy, don't copy to output file */
216 /* otherwise copy original line to output */
217 fprintf(nf, "%s", nbuffer);
220 rx_identity_freeContents(&identity);
225 if (fclose(nf) == EOF)
227 strcpy(nbuffer, tbuffer);
228 strcat(nbuffer, ".NXX"); /* generate new file name again */
231 flag = renamefile(nbuffer, tbuffer);
233 flag = chmod(tbuffer, tstat.st_mode);
237 /* finally, decide what to return to the caller */
240 return EIO; /* something mysterious went wrong */
242 return ENOENT; /* entry wasn't found, no changes made */
243 return 0; /* everything was fine */
247 * Remove a legacy Kerberos 4 name from the UserList file.
249 * This function removes a Kerberos 4 name from the super user list. It
250 * can only remove names which were added by the afsconf_AddUser interface,
251 * or with an explicit Kerberos v4 type.
254 * A structure representing the configuration directory
256 * The Kerberos v4 name to remove
259 * 0 on success, an error code upon failure.
261 * Note that this function is deprecated. New callers should use
262 * afsconf_DeleteIdentity instead.
266 afsconf_DeleteUser(struct afsconf_dir *adir, char *name)
268 struct rx_identity *user;
271 user = rx_identity_new(RX_ID_KRB4, name, name, strlen(name));
275 code = afsconf_DeleteIdentity(adir, user);
277 rx_identity_free(&user);
282 /* This is a multi-purpose funciton for use by either
283 * GetNthIdentity or GetNthUser. The parameter 'id' indicates
284 * whether we are counting all identities (if true), or just
285 * ones which can be represented by the old-style interfaces
288 GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
289 struct rx_identity **identity, int id)
293 struct rx_identity fileUser;
297 UserListFileName(dir, tbuffer, sizeof(tbuffer));
298 bp = BufioOpen(tbuffer, O_RDONLY, 0);
304 code = BufioGets(bp, tbuffer, sizeof(tbuffer));
308 code = ParseLine(tbuffer, &fileUser);
312 if (id || fileUser.kind == RX_ID_KRB4)
318 rx_identity_freeContents(&fileUser);
321 *identity = rx_identity_copy(&fileUser);
322 rx_identity_freeContents(&fileUser);
332 * Return the Nth super user identity from the UserList
335 * A structure representing the configuration directory
337 * A count (from zero) of the entries to return from the
339 * @param[out] identity
340 * A pointer to the Nth identity
342 * 0 on success, non-zero on failure
346 afsconf_GetNthIdentity(struct afsconf_dir *dir, int count,
347 struct rx_identity **identity)
349 return GetNthIdentityOrUser(dir, count, identity, 1);
353 * Return the Nth Kerberos v4 identity from the UserList
355 * This returns the Nth old, kerberos v4 style name from
356 * the UserList file. In counting entries it skips any other
357 * name types it encounters - so will hide any new-style
358 * identities from its callers.
361 * A structure representing the configuration directory
363 * A count (from zero) of the entries to return from the
366 * A string in which to write the name of the Nth identity
368 * The length of the buffer passed in abuffer
370 * 0 on success, non-zero on failure
372 * This function is deprecated, all new callers should use
373 * GetNthIdentity instead. This function is particularly dangerous
374 * as it will hide any new-style identities from callers.
378 afsconf_GetNthUser(struct afsconf_dir *adir, afs_int32 an, char *abuffer,
379 afs_int32 abufferLen)
381 struct rx_identity *identity;
384 code = GetNthIdentityOrUser(adir, an, &identity, 0);
386 strlcpy(abuffer, identity->displayName, abufferLen);
387 rx_identity_free(&identity);
393 * Parse a UserList list
395 * Parse a line of data from a UserList file
397 * This parses a line of data in a UserList, and populates the passed
398 * rx_identity structure with the information about the user.
400 * @param buffer A string containing the line to be parsed
401 * @param user The user structure to be populated
403 * Note that the user->displayName, and user->exportedName.val fields
404 * must be freed with free() by the caller.
406 * This function damages the buffer thats passed to it. Callers are
407 * expected to make a copy if they want the buffer preserved.
410 * 0 on success, non-zero on failure.
414 ParseLine(char *buffer, struct rx_identity *user)
425 if (buffer[0] == ' ') { /* extended names have leading space */
427 code = sscanf(ptr, "%i", &kind);
431 strsep(&ptr, " "); /* skip the bit we just read with scanf */
432 ename = strsep(&ptr, " "); /* Pull out the ename */
433 displayName = strsep(&ptr, " "); /* Display name runs to the end */
434 if (ename == NULL || displayName == NULL)
437 decodedName = malloc(strlen(ename));
438 if (decodedName == NULL)
441 len = base64_decode(ename, decodedName);
447 rx_identity_populate(user, kind, displayName, decodedName, len);
450 return 0; /* Success ! */
453 /* No extended name, try for a legacy name */
454 code = sscanf(buffer, "%64s", name);
458 rx_identity_populate(user, RX_ID_KRB4, name, name, strlen(name));
463 * Check if a given identity is in the UserList file,
464 * and thus is a super user
467 * A structure representing the configuration directory to check
469 * The identity to check
471 * True if the user is listed in the UserList, otherwise false
475 afsconf_IsSuperIdentity(struct afsconf_dir *adir,
476 struct rx_identity *user)
480 struct rx_identity fileUser;
484 UserListFileName(adir, tbuffer, sizeof tbuffer);
485 bp = BufioOpen(tbuffer, O_RDONLY, 0);
490 code = BufioGets(bp, tbuffer, sizeof(tbuffer));
494 code = ParseLine(tbuffer, &fileUser);
498 match = rx_identity_match(user, &fileUser);
500 rx_identity_freeContents(&fileUser);
506 /* add a user to the user list, checking for duplicates */
508 afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
516 if (afsconf_IsSuperIdentity(adir, user)) {
518 return EEXIST; /* already in the list */
521 UserListFileName(adir, tbuffer, sizeof tbuffer);
522 tf = fopen(tbuffer, "a+");
527 if (user->kind == RX_ID_KRB4) {
528 fprintf(tf, "%s\n", user->displayName);
530 base64_encode(user->exportedName.val, user->exportedName.len,
532 fprintf(tf, " %d %s %s\n", user->kind, ename, user->displayName);
545 afsconf_AddUser(struct afsconf_dir *adir, char *aname)
547 struct rx_identity *user;
550 user = rx_identity_new(RX_ID_KRB4, aname, aname, strlen(aname));
554 code = afsconf_AddIdentity(adir, user);
556 rx_identity_free(&user);
561 /* special CompFindUser routine that builds up a princ and then
562 calls finduser on it. If found, returns char * to user string,
563 otherwise returns NULL. The resulting string should be immediately
564 copied to other storage prior to release of mutex. */
566 CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
567 char *realm, struct rx_identity **identity)
569 static char fullname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
570 struct rx_identity *testId;
572 /* always must have name */
573 if (!name || !name[0]) {
576 strcpy(fullname, name);
578 /* might have instance */
579 if (inst && inst[0]) {
580 if (!sep || !sep[0]) {
584 strcat(fullname, sep);
585 strcat(fullname, inst);
588 /* might have realm */
589 if (realm && realm[0]) {
590 strcat(fullname, "@");
591 strcat(fullname, realm);
594 testId = rx_identity_new(RX_ID_KRB4, fullname, fullname, strlen(fullname));
595 if (afsconf_IsSuperIdentity(adir, testId)) {
599 rx_identity_free(&testId);
603 rx_identity_free(&testId);
608 kerberosSuperUser(struct afsconf_dir *adir, char *tname, char *tinst,
609 char *tcell, struct rx_identity **identity)
611 char tcell_l[MAXKTCREALMLEN] = "";
613 static char lcell[MAXCELLCHARS] = "";
614 static char lrealms[AFS_NUM_LREALMS][AFS_REALM_SZ];
615 static int num_lrealms = -1;
616 int lrealm_match = 0, i;
619 /* generate lowercased version of cell name */
621 strcpy(tcell_l, tcell);
624 *tmp = tolower(*tmp);
629 /* determine local cell name. It's static, so will only get
630 * calculated the first time through */
632 afsconf_GetLocalCell(adir, lcell, sizeof(lcell));
634 /* if running a krb environment, also get the local realm */
635 /* note - this assumes AFS_REALM_SZ <= MAXCELLCHARS */
636 /* just set it to lcell if it fails */
637 if (num_lrealms == -1) {
638 for (i=0; i<AFS_NUM_LREALMS; i++) {
639 if (afs_krb_get_lrealm(lrealms[i], i) != 0 /*KSUCCESS*/)
644 strncpy(lrealms[0], lcell, AFS_REALM_SZ);
651 /* See if the ticket cell matches one of the local realms */
653 for ( i=0;i<num_lrealms;i++ ) {
654 if (!strcasecmp(lrealms[i], tcell)) {
660 /* If yes, then make sure that the name is not present in
661 * an exclusion list */
663 char uname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
664 if (tinst && tinst[0])
665 snprintf(uname,sizeof(uname),"%s.%s@%s",tname,tinst,tcell);
667 snprintf(uname,sizeof(uname),"%s@%s",tname,tcell);
669 if (afs_krb_exclusion(uname))
673 /* start with no authorization */
676 /* localauth special case */
677 if ((tinst == NULL || strlen(tinst) == 0) &&
678 (tcell == NULL || strlen(tcell) == 0)
679 && !strcmp(tname, AUTH_SUPERUSER)) {
681 *identity = rx_identity_new(RX_ID_KRB4, AFS_LOCALAUTH_NAME,
682 AFS_LOCALAUTH_NAME, AFS_LOCALAUTH_LEN);
685 /* cell of connection matches local cell or one of the realms */
686 } else if (!strcasecmp(tcell, lcell) || lrealm_match) {
687 if (CompFindUser(adir, tname, ".", tinst, NULL, identity)) {
690 /* cell of conn doesn't match local cell or realm */
692 if (CompFindUser(adir, tname, ".", tinst, tcell, identity)) {
694 } else if (CompFindUser(adir, tname, ".", tinst, tcell_l, identity)) {
703 rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
704 struct rx_identity **identity)
706 char tname[MAXKTCNAMELEN]; /* authentication from ticket */
707 char tinst[MAXKTCNAMELEN];
708 char tcell[MAXKTCREALMLEN];
713 /* get auth details from server connection */
714 code = rxkad_GetServerInfo(acall->conn, NULL, &exp, tname, tinst, tcell,
717 return 0; /* bogus connection/other error */
719 return kerberosSuperUser(adir, tname, tinst, tcell, identity);
723 * Check whether the user authenticated on a given RX call is a super
724 * user or not. If they are, return a pointer to the identity of that
728 * The configuration directory currently in use
730 * The RX call whose authenticated identity is being checked
731 * @param[out] identity
732 * The RX identity of the user. Caller must free this structure.
734 * True if the user is a super user, or if the server is running
735 * in noauth mode. Otherwise, false.
738 afsconf_SuperIdentity(struct afsconf_dir *adir, struct rx_call *acall,
739 struct rx_identity **identity)
741 struct rx_connection *tconn;
751 if (afsconf_GetNoAuthFlag(adir)) {
753 *identity = rx_identity_new(RX_ID_KRB4, AFS_NOAUTH_NAME,
754 AFS_NOAUTH_NAME, AFS_NOAUTH_LEN);
759 tconn = rx_ConnectionOf(acall);
760 code = rx_SecurityClassOf(tconn);
763 return 0; /* not authenticated at all, answer is no */
764 } else if (code == 1) {
767 return 0; /* not supported any longer */
768 } else if (code == 2) {
769 flag = rxkadSuperUser(adir, acall, identity);
772 } else { /* some other auth type */
774 return 0; /* mysterious, just say no */
779 * Check whether the user authenticated on a given RX call is a super
780 * user or not. If they are, return a pointer to the name of that
784 * The configuration directory currently in use
786 * The RX call whose authenticated identity is being checked
788 * A printable version of the name of the user
790 * True if the user is a super user, or if the server is running
791 * in noauth mode. Otherwise, false.
793 * This function is provided for backwards compatibility. New callers
794 * should use the afsconf_SuperIdentity function.
798 afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall,
801 struct rx_identity *identity;
805 ret = afsconf_SuperIdentity(adir, acall, &identity);
807 if (identity->kind == RX_ID_KRB4) {
808 strlcpy(namep, identity->displayName, MAXKTCNAMELEN-1);
810 snprintf(namep, MAXKTCNAMELEN-1, "eName: %s",
811 identity->displayName);
813 rx_identity_free(&identity);
816 ret = afsconf_SuperIdentity(adir, acall, NULL);