userok.c: Fix fixed-size on-stack path buffers
[openafs.git] / src / auth / userok.c
index 52dd467..326a736 100644 (file)
@@ -9,45 +9,31 @@
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
 #include <roken.h>
-#include "base64.h"
+#include <afs/opr.h>
 
-#include <afs/stds.h>
-#include <afs/pthread_glock.h>
-#include <sys/types.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <sys/file.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <unistd.h>
-#endif
-#include <sys/stat.h>
-#include <stdlib.h>            /* for realpath() */
-#include <errno.h>
-#include <string.h>
 #include <ctype.h>
 
+#include <afs/pthread_glock.h>
 #include <rx/xdr.h>
 #include <rx/rx.h>
 #include <rx/rx_identity.h>
-#include <stdio.h>
 #include <afs/afsutil.h>
 #include <afs/fileutil.h>
 
-#ifdef AFS_ATHENA_STDENV
-#include <krb.h>
-#endif
-
+#include "base64.h"
 #include "auth.h"
 #include "cellconfig.h"
 #include "keys.h"
 #include "afs/audit.h"
 
+/* The display names for localauth and noauth identities; they aren't used
+ * inside tickets or anything, but just serve as something to display in logs,
+ * etc. */
+#define AFS_LOCALAUTH_NAME "<LocalAuth>"
+#define AFS_LOCALAUTH_LEN  (sizeof(AFS_LOCALAUTH_NAME)-1)
 #define AFS_NOAUTH_NAME "<NoAuth>"
 #define AFS_NOAUTH_LEN  (sizeof(AFS_NOAUTH_NAME)-1)
 
@@ -57,8 +43,7 @@ static void
 UserListFileName(struct afsconf_dir *adir,
                 char *buffer, size_t len)
 {
-    strcompose(buffer, len, adir->name, "/",
-              AFSDIR_ULIST_FILE, NULL);
+    strcompose(buffer, len, adir->name, "/", AFSDIR_ULIST_FILE, (char *)NULL);
 }
 
 #if !defined(UKERNEL)
@@ -142,8 +127,8 @@ afsconf_SetNoAuthFlag(struct afsconf_dir *adir, int aflag)
 int
 afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
 {
-    char tbuffer[1024];
-    char nbuffer[1024];
+    char *filename, *nfilename;
+    char *buffer;
     char *copy;
     FILE *tf;
     FILE *nf;
@@ -154,8 +139,19 @@ afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
     struct rx_identity identity;
     afs_int32 code;
 
+    memset(&identity, 0, sizeof(struct rx_identity));
+
+    buffer = malloc(AFSDIR_PATH_MAX);
+    if (buffer == NULL)
+       return ENOMEM;
+    filename = malloc(AFSDIR_PATH_MAX);
+    if (filename == NULL) {
+       free(buffer);
+       return ENOMEM;
+    }
+
     LOCK_GLOBAL_MUTEX;
-    UserListFileName(adir, tbuffer, sizeof tbuffer);
+    UserListFileName(adir, filename, AFSDIR_PATH_MAX);
 #ifndef AFS_NT40_ENV
     {
        /*
@@ -163,40 +159,61 @@ afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
         * 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);
+       nfilename = malloc(AFSDIR_PATH_MAX);
+       if (nfilename == NULL) {
+           UNLOCK_GLOBAL_MUTEX;
+           free(filename);
+           free(buffer);
+           return ENOMEM;
+       }
+       if (realpath(filename, nfilename)) {
+           free(filename);
+           filename = nfilename;
+       } else {
+           free(nfilename);
        }
     }
 #endif /* AFS_NT40_ENV */
-    tf = fopen(tbuffer, "r");
+    if (asprintf(&nfilename, "%s.NXX", filename) < 0) {
+       UNLOCK_GLOBAL_MUTEX;
+       free(filename);
+       free(buffer);
+       return -1;
+    }
+    tf = fopen(filename, "r");
     if (!tf) {
        UNLOCK_GLOBAL_MUTEX;
+       free(filename);
+       free(nfilename);
+       free(buffer);
        return -1;
     }
-    code = stat(tbuffer, &tstat);
+    code = stat(filename, &tstat);
     if (code < 0) {
        UNLOCK_GLOBAL_MUTEX;
+       free(filename);
+       free(nfilename);
+       free(buffer);
        return code;
     }
-    strcpy(nbuffer, tbuffer);
-    strcat(nbuffer, ".NXX");
-    nf = fopen(nbuffer, "w+");
+    nf = fopen(nfilename, "w+");
     if (!nf) {
        fclose(tf);
        UNLOCK_GLOBAL_MUTEX;
+       free(filename);
+       free(nfilename);
+       free(buffer);
        return EIO;
     }
     flag = 0;
     found = 0;
     while (1) {
        /* check for our user id */
-       tp = fgets(nbuffer, sizeof(nbuffer), tf);
+       tp = fgets(buffer, AFSDIR_PATH_MAX, tf);
        if (tp == NULL)
            break;
 
-       copy = strdup(nbuffer);
+       copy = strdup(buffer);
        if (copy == NULL) {
            flag = 1;
            break;
@@ -207,28 +224,29 @@ afsconf_DeleteIdentity(struct afsconf_dir *adir, struct rx_identity *user)
            found = 1;
        } else {
            /* otherwise copy original line to output */
-           fprintf(nf, "%s", nbuffer);
+           fprintf(nf, "%s", buffer);
        }
        free(copy);
        rx_identity_freeContents(&identity);
     }
     fclose(tf);
+    free(buffer);
     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);
+       flag = rk_rename(nfilename, filename);
        if (flag == 0)
-           flag = chmod(tbuffer, tstat.st_mode);
+           flag = chmod(filename, tstat.st_mode);
     } else
-       unlink(nbuffer);
+       unlink(nfilename);
 
     /* finally, decide what to return to the caller */
     UNLOCK_GLOBAL_MUTEX;
+    free(filename);
+    free(nfilename);
     if (flag)
        return EIO;             /* something mysterious went wrong */
     if (!found)
@@ -282,19 +300,24 @@ GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
                     struct rx_identity **identity, int id)
 {
     bufio_p bp;
-    char tbuffer[1024];
+    char *tbuffer;
     struct rx_identity fileUser;
     afs_int32 code;
 
+    tbuffer = malloc(AFSDIR_PATH_MAX);
+    if (tbuffer == NULL)
+       return ENOMEM;
+
     LOCK_GLOBAL_MUTEX;
-    UserListFileName(dir, tbuffer, sizeof(tbuffer));
+    UserListFileName(dir, tbuffer, AFSDIR_PATH_MAX);
     bp = BufioOpen(tbuffer, O_RDONLY, 0);
     if (!bp) {
        UNLOCK_GLOBAL_MUTEX;
+       free(tbuffer);
        return EIO;
     }
     while (1) {
-       code = BufioGets(bp, tbuffer, sizeof(tbuffer));
+       code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
        if (code < 0)
            break;
 
@@ -318,6 +341,7 @@ GetNthIdentityOrUser(struct afsconf_dir *dir, int count,
     BufioClose(bp);
 
     UNLOCK_GLOBAL_MUTEX;
+    free(tbuffer);
     return code;
 }
 
@@ -469,19 +493,24 @@ afsconf_IsSuperIdentity(struct afsconf_dir *adir,
                        struct rx_identity *user)
 {
     bufio_p bp;
-    char tbuffer[1024];
+    char *tbuffer;
     struct rx_identity fileUser;
     int match;
     afs_int32 code;
 
-    strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE,
-              NULL);
+    tbuffer = malloc(AFSDIR_PATH_MAX);
+    if (tbuffer == NULL)
+       return 0;
+
+    UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
     bp = BufioOpen(tbuffer, O_RDONLY, 0);
-    if (!bp)
+    if (!bp) {
+       free(tbuffer);
        return 0;
+    }
     match = 0;
     while (!match) {
-       code = BufioGets(bp, tbuffer, sizeof(tbuffer));
+       code = BufioGets(bp, tbuffer, AFSDIR_PATH_MAX);
         if (code < 0)
            break;
 
@@ -494,6 +523,7 @@ afsconf_IsSuperIdentity(struct afsconf_dir *adir,
        rx_identity_freeContents(&fileUser);
     }
     BufioClose(bp);
+    free(tbuffer);
     return match;
 }
 
@@ -504,7 +534,7 @@ afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
     FILE *tf;
     afs_int32 code;
     char *ename;
-    char tbuffer[256];
+    char *tbuffer;
 
     LOCK_GLOBAL_MUTEX;
     if (afsconf_IsSuperIdentity(adir, user)) {
@@ -512,9 +542,10 @@ afsconf_AddIdentity(struct afsconf_dir *adir, struct rx_identity *user)
        return EEXIST;          /* already in the list */
     }
 
-    strcompose(tbuffer, sizeof tbuffer, adir->name, "/", AFSDIR_ULIST_FILE,
-              NULL);
+    tbuffer = malloc(AFSDIR_PATH_MAX);
+    UserListFileName(adir, tbuffer, AFSDIR_PATH_MAX);
     tf = fopen(tbuffer, "a+");
+    free(tbuffer);
     if (!tf) {
        UNLOCK_GLOBAL_MUTEX;
        return EIO;
@@ -568,7 +599,9 @@ CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
     if (!name || !name[0]) {
        return 0;
     }
-    strcpy(fullname, name);
+
+    if (strlcpy(fullname, name, sizeof(fullname)) >= sizeof(fullname))
+       return 0;
 
     /* might have instance */
     if (inst && inst[0]) {
@@ -576,19 +609,25 @@ CompFindUser(struct afsconf_dir *adir, char *name, char *sep, char *inst,
            return 0;
        }
 
-       strcat(fullname, sep);
-       strcat(fullname, inst);
+       if (strlcat(fullname, sep, sizeof(fullname)) >= sizeof(fullname))
+           return 0;
+
+       if (strlcat(fullname, inst, sizeof(fullname)) >= sizeof(fullname))
+           return 0;
     }
 
     /* might have realm */
     if (realm && realm[0]) {
-       strcat(fullname, "@");
-       strcat(fullname, realm);
+       if (strlcat(fullname, "@", sizeof(fullname)) >= sizeof(fullname))
+           return 0;
+
+       if (strlcat(fullname, realm, sizeof(fullname)) >= sizeof(fullname))
+           return 0;
     }
 
     testId = rx_identity_new(RX_ID_KRB4, fullname, fullname, strlen(fullname));
     if (afsconf_IsSuperIdentity(adir, testId)) {
-       if (*identity)
+       if (identity)
             *identity = testId;
        else
             rx_identity_free(&testId);
@@ -604,83 +643,33 @@ kerberosSuperUser(struct afsconf_dir *adir, char *tname, char *tinst,
                  char *tcell, struct rx_identity **identity)
 {
     char tcell_l[MAXKTCREALMLEN] = "";
-    char *tmp;
-
-    /* keep track of which one actually authorized request */
-    char uname[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
-
-    static char lcell[MAXCELLCHARS] = "";
-    static char lrealms[AFS_NUM_LREALMS][AFS_REALM_SZ];
-    static int  num_lrealms = -1;
-    int lrealm_match = 0, i;
+    int code;
+    afs_int32 islocal;
     int flag;
 
     /* generate lowercased version of cell name */
-    if (tcell) {
-       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 (num_lrealms == -1) {
-       for (i=0; i<AFS_NUM_LREALMS; i++) {
-           if (afs_krb_get_lrealm(lrealms[i], i) != 0 /*KSUCCESS*/)
-               break;
-       }
-
-       if (i == 0) {
-           strncpy(lrealms[0], lcell, AFS_REALM_SZ);
-           num_lrealms = 1;
-       } else {
-           num_lrealms = i;
-       }
-    }
+    if (tcell)
+       opr_lcstring(tcell_l, tcell, sizeof(tcell_l));
 
-    /* See if the ticket cell matches one of the local realms */
-    lrealm_match = 0;
-    for ( i=0;i<num_lrealms;i++ ) {
-       if (!strcasecmp(lrealms[i], tcell)) {
-           lrealm_match = 1;
-           break;
-       }
-    }
-
-    /* If yes, then make sure that the name is not present in
-     * an exclusion list */
-    if (lrealm_match) {
-       if (tinst && tinst[0])
-           snprintf(uname,sizeof(uname),"%s.%s@%s",tname,tinst,tcell);
-       else
-           snprintf(uname,sizeof(uname),"%s@%s",tname,tcell);
-
-       if (afs_krb_exclusion(uname))
-           lrealm_match = 0;
+    code = afsconf_IsLocalRealmMatch(adir, &islocal, tname, tinst, tcell);
+    if (code) {
+       return 0;
     }
 
-    /* start with no uname and no authorization */
-    strcpy(uname, "");
+    /* start with no authorization */
     flag = 0;
 
     /* localauth special case */
     if ((tinst == NULL || strlen(tinst) == 0) &&
        (tcell == NULL || strlen(tcell) == 0)
        && !strcmp(tname, AUTH_SUPERUSER)) {
-       strcpy(uname, "<LocalAuth>");
+       if (identity)
+           *identity = rx_identity_new(RX_ID_KRB4, AFS_LOCALAUTH_NAME,
+                                       AFS_LOCALAUTH_NAME, AFS_LOCALAUTH_LEN);
        flag = 1;
 
        /* cell of connection matches local cell or one of the realms */
-    } else if (!strcasecmp(tcell, lcell) || lrealm_match) {
+    } else if (islocal) {
        if (CompFindUser(adir, tname, ".", tinst, NULL, identity)) {
            flag = 1;
        }
@@ -708,8 +697,8 @@ rxkadSuperUser(struct afsconf_dir *adir, struct rx_call *acall,
     int code;
 
     /* get auth details from server connection */
-    code = rxkad_GetServerInfo(acall->conn, NULL, &exp, tname, tinst, tcell,
-                              NULL);
+    code = rxkad_GetServerInfo(rx_ConnectionOf(acall), NULL, &exp, tname,
+                              tinst, tcell, NULL);
     if (code)
        return 0;               /* bogus connection/other error */
 
@@ -796,20 +785,22 @@ afsconf_SuperUser(struct afsconf_dir *adir, struct rx_call *acall,
                  char *namep)
 {
     struct rx_identity *identity;
-    int code;
+    int ret;
 
-    code = afsconf_SuperIdentity(adir, acall, &identity);
-    if (code) {
-       if (namep) {
+    if (namep) {
+       ret = afsconf_SuperIdentity(adir, acall, &identity);
+       if (ret) {
            if (identity->kind == RX_ID_KRB4) {
                strlcpy(namep, identity->displayName, MAXKTCNAMELEN-1);
            } else {
                snprintf(namep, MAXKTCNAMELEN-1, "eName: %s",
                         identity->displayName);
            }
+           rx_identity_free(&identity);
        }
-       rx_identity_free(&identity);
+    } else {
+       ret = afsconf_SuperIdentity(adir, acall, NULL);
     }
 
-    return code;
+    return ret;
 }