krb5-no-dot-20041017
[openafs.git] / src / WINNT / afsd / afskfw.c
index 6a80b6a..743374a 100644 (file)
@@ -62,6 +62,7 @@
 
 #include <osilog.h>
 #include <rxkad_prototypes.h>   /* for life_to_time */
+#include <afs/ptserver.h>
 
 /*
  * TIMING _____________________________________________________________________
@@ -340,7 +341,7 @@ FUNC_INFO lsa_fi[] = {
 #endif /* USE_MS2MIT */
 
 /* Static Prototypes */
-char *afs_realm_of_cell(struct afsconf_cell *);
+char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *);
 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
@@ -359,8 +360,6 @@ static HINSTANCE hKrb524 = 0;
 static HINSTANCE hSecur32 = 0;
 #endif /* USE_MS2MIT */
 static HINSTANCE hAdvApi32 = 0;
-static HINSTANCE hAfsTokens = 0;
-static HINSTANCE hAfsConf = 0;
 static HINSTANCE hComErr = 0;
 static HINSTANCE hService = 0;
 static HINSTANCE hProfile = 0;
@@ -427,10 +426,6 @@ KFW_cleanup(void)
         FreeLibrary(hKrb4);
     if (hProfile)
         FreeLibrary(hProfile);
-    if (hAfsTokens)
-        FreeLibrary(hAfsTokens);
-    if (hAfsConf)
-        FreeLibrary(hAfsConf);
     if (hComErr)
         FreeLibrary(hComErr);
     if (hService)
@@ -449,28 +444,65 @@ KFW_cleanup(void)
 
 static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client";
 
+int
+KFW_use_krb524(void)
+{
+    HKEY parmKey;
+    DWORD code, len;
+    DWORD use524 = 0;
+
+    code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        len = sizeof(use524);
+        code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
+                                (BYTE *) &use524, &len);
+        if (code != ERROR_SUCCESS) {
+            RegCloseKey(parmKey);
+
+            code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+                                 0, KEY_QUERY_VALUE, &parmKey);
+            if (code == ERROR_SUCCESS) {
+                len = sizeof(use524);
+                code = RegQueryValueEx(parmKey, "Use524", NULL, NULL,
+                                        (BYTE *) &use524, &len);
+                if (code != ERROR_SUCCESS)
+                    use524 = 0;
+            }
+        }
+        RegCloseKey (parmKey);
+    }
+    return use524;
+}
+
 int 
 KFW_is_available(void)
 {
     HKEY parmKey;
-       DWORD code, len;
+    DWORD code, len;
     DWORD enableKFW = 1;
 
     code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName,
                          0, KEY_QUERY_VALUE, &parmKey);
-    if (code != ERROR_SUCCESS)
-        code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
-                             0, KEY_QUERY_VALUE, &parmKey);
-       if (code == ERROR_SUCCESS) {
+    if (code == ERROR_SUCCESS) {
         len = sizeof(enableKFW);
         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
                                 (BYTE *) &enableKFW, &len);
         if (code != ERROR_SUCCESS) {
-            enableKFW = 1;
+            RegCloseKey(parmKey);
+
+            code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName,
+                                 0, KEY_QUERY_VALUE, &parmKey);
+            if (code == ERROR_SUCCESS) {
+                len = sizeof(enableKFW);
+                code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
+                                        (BYTE *) &enableKFW, &len);
+                if (code != ERROR_SUCCESS)
+                    enableKFW = 1;
+            }
         }
         RegCloseKey (parmKey);
-       }
-
+    }
     if ( !enableKFW )
         return FALSE;
 
@@ -480,7 +512,7 @@ KFW_is_available(void)
          hSecur32 && 
 #endif /* USE_MS2MIT */
          hKrb524 &&
-         hProfile && hAfsTokens && hAfsConf && hLeash && hCCAPI )
+         hProfile && hLeash && hCCAPI )
         return TRUE;
     return FALSE;
 }
@@ -866,9 +898,9 @@ KFW_import_windows_lsa(void)
     krb5_ccache  cc = 0;
     krb5_principal princ = 0;
     char * pname = NULL;
-    krb5_data *  realm;
+    krb5_data *  princ_realm;
     krb5_error_code code;
-    char cell[128]="";
+    char cell[128]="", realm[128]="";
     int i;
          
     if (!pkrb5_init_context)
@@ -893,13 +925,15 @@ KFW_import_windows_lsa(void)
     code = pkrb5_unparse_name(ctx,princ,&pname);
     if ( code ) goto cleanup;
 
-    realm = krb5_princ_realm(ctx, princ);
-    for ( i=0; i<realm->length; i++ ) {
-        cell[i] = tolower(realm->data[i]);
+    princ_realm = krb5_princ_realm(ctx, princ);
+    for ( i=0; i<princ_realm->length; i++ ) {
+        realm[i] = princ_realm->data[i];
+        cell[i] = tolower(princ_realm->data[i]);
     }
-       cell[i] = '\0';
+    cell[i] = '\0';
+    realm[i] = '\0';
 
-    code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime(),NULL);
+    code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, pLeash_get_default_lifetime(),NULL);
     if ( IsDebuggerPresent() ) {
         char message[256];
         sprintf(message,"KFW_AFS_klog() returns: %d\n",code);
@@ -1122,7 +1156,7 @@ KFW_import_ccache_data(void)
 
 
 int
-KFW_AFS_get_cred(char * username, 
+KFW_AFS_get_cred( char * username, 
                   char * cell,
                   char * password,
                   int lifetime,
@@ -1140,6 +1174,8 @@ KFW_AFS_get_cred(char * username,
     char **cells = NULL;
     int  cell_count=0;
     struct afsconf_cell cellconfig;
+    char * dot;
+
 
     if (!pkrb5_init_context)
         return 0;
@@ -1159,12 +1195,30 @@ KFW_AFS_get_cred(char * username,
     if ( code ) goto cleanup;
 
     realm = strchr(username,'@');
-    if (realm) {
+    if ( realm ) {
+        pname = strdup(username);
+        realm = strchr(pname, '@');
         *realm = '\0';
-        realm++;
+
+        /* handle kerberos iv notation */
+        while ( dot = strchr(pname,'.') ) {
+            *dot = '/';
+        }
+        *realm++ = '@';
+    } else {
+        realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
+        pname = malloc(strlen(username) + strlen(realm) + 2);
+
+        strcpy(pname, username);
+
+        /* handle kerberos iv notation */
+        while ( dot = strchr(pname,'.') ) {
+            *dot = '/';
+        }
+
+        strcat(pname,"@");
+        strcat(pname,realm);
     }
-    if ( !realm || !realm[0] )
-        realm = afs_realm_of_cell(&cellconfig);  // do not free
 
     if ( IsDebuggerPresent() ) {
         OutputDebugString("Realm: ");
@@ -1172,37 +1226,34 @@ KFW_AFS_get_cred(char * username,
         OutputDebugString("\n");
     }
 
-    code = pkrb5_build_principal(ctx, &principal, strlen(realm),
-                                 realm, username,
-                                 NULL,
-                                 NULL);
-
-    code = KFW_get_ccache(ctx, principal, &cc);
+    code = pkrb5_parse_name(ctx, pname, &principal);
     if ( code ) goto cleanup;
 
-    code = pkrb5_unparse_name(ctx, principal, &pname);
+    code = KFW_get_ccache(ctx, principal, &cc);
     if ( code ) goto cleanup;
 
     if ( lifetime == 0 )
         lifetime = pLeash_get_default_lifetime();
 
-    code = KFW_kinit(ctx, cc, HWND_DESKTOP, 
-                      pname, 
-                      password,
-                      lifetime,
-                      pLeash_get_default_forwardable(),
-                      pLeash_get_default_proxiable(),
-                      pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
-                      pLeash_get_default_noaddresses(),
-                      pLeash_get_default_publicip());
-    if ( IsDebuggerPresent() ) {
-        char message[256];
-        sprintf(message,"KFW_kinit() returns: %d\n",code);
-        OutputDebugString(message);
+    if ( password && password[0] ) {
+        code = KFW_kinit( ctx, cc, HWND_DESKTOP, 
+                          pname, 
+                          password,
+                          lifetime,
+                          pLeash_get_default_forwardable(),
+                          pLeash_get_default_proxiable(),
+                          pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
+                          pLeash_get_default_noaddresses(),
+                          pLeash_get_default_publicip());
+        if ( IsDebuggerPresent() ) {
+            char message[256];
+            sprintf(message,"KFW_kinit() returns: %d\n",code);
+            OutputDebugString(message);
+        }
+        if ( code ) goto cleanup;
+
+        KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
     }
-    if ( code ) goto cleanup;
-                   
-    KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE);
 
     code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime,smbname);
     if ( IsDebuggerPresent() ) {
@@ -1228,7 +1279,7 @@ KFW_AFS_get_cred(char * username,
                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                 if ( code ) continue;
     
-                realm = afs_realm_of_cell(&cellconfig);  // do not free
+                realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
                 if ( IsDebuggerPresent() ) {
                     OutputDebugString("Realm: ");
                     OutputDebugString(realm);
@@ -1252,7 +1303,7 @@ KFW_AFS_get_cred(char * username,
 
   cleanup:
     if ( pname )
-        pkrb5_free_unparsed_name(ctx,pname);
+        free(pname);
     if ( cc )
         pkrb5_cc_close(ctx, cc);
 
@@ -1393,7 +1444,7 @@ KFW_AFS_renew_expiring_tokens(void)
                     }
                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
                     if ( code ) continue;
-                    realm = afs_realm_of_cell(&cellconfig);  // do not free
+                    realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
                     if ( IsDebuggerPresent() ) {
                         OutputDebugString("Realm: ");
                         OutputDebugString(realm);
@@ -1477,7 +1528,7 @@ KFW_AFS_renew_token_for_cell(char * cell)
             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
             if ( code ) goto loop_cleanup;
 
-            realm = afs_realm_of_cell(&cellconfig);  // do not free
+            realm = afs_realm_of_cell(ctx, &cellconfig);  // do not free
             if ( IsDebuggerPresent() ) {
                 OutputDebugString("Realm: ");
                 OutputDebugString(realm);
@@ -2365,6 +2416,114 @@ KFW_AFS_unlog(void)
     return(0);
 }
 
+
+#define ALLOW_REGISTER 1
+static int
+ViceIDToUsername(char *username, 
+                 char *realm_of_user, 
+                 char *realm_of_cell,
+                 char * cell_to_use,
+                 struct ktc_principal *aclient, 
+                 struct ktc_principal *aserver, 
+                 struct ktc_token *atoken)
+{
+    static char lastcell[MAXCELLCHARS+1] = { 0 };
+    static char confname[512] = { 0 };
+    char username_copy[BUFSIZ];
+    long viceId;                       /* AFS uid of user */
+    int  status = 0;
+#ifdef ALLOW_REGISTER
+    afs_int32 id;
+#endif /* ALLOW_REGISTER */
+
+    if (confname[0] == '\0') {
+        strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
+        confname[sizeof(confname) - 2] = '\0';
+    }
+
+    /*
+     * Talk about DUMB!  It turns out that there is a bug in
+     * pr_Initialize -- even if you give a different cell name
+     * to it, it still uses a connection to a previous AFS server
+     * if one exists.  The way to fix this is to change the
+     * _filename_ argument to pr_Initialize - that forces it to
+     * re-initialize the connection.  We do this by adding and
+     * removing a "/" on the end of the configuration directory name.
+     */
+
+    if (lastcell[0] != '\0' && (strcmp(lastcell, aserver->cell) != 0)) {
+        int i = strlen(confname);
+        if (confname[i - 1] == '/') {
+            confname[i - 1] = '\0';
+        } else {
+            confname[i] = '/';
+            confname[i + 1] = '\0';
+        }
+    }
+
+    strcpy(lastcell, aserver->cell);
+
+    if (!pr_Initialize (0, confname, aserver->cell))
+        status = pr_SNameToId (username, &viceId);
+
+    /*
+     * This is a crock, but it is Transarc's crock, so
+     * we have to play along in order to get the
+     * functionality.  The way the afs id is stored is
+     * as a string in the username field of the token.
+     * Contrary to what you may think by looking at
+     * the code for tokens, this hack (AFS ID %d) will
+     * not work if you change %d to something else.
+     */
+
+    /*
+     * This code is taken from cklog -- it lets people
+     * automatically register with the ptserver in foreign cells
+     */
+
+#ifdef ALLOW_REGISTER
+    if (status == 0) {
+        if (viceId != ANONYMOUSID) {
+#else /* ALLOW_REGISTER */
+            if ((status == 0) && (viceId != ANONYMOUSID))
+#endif /* ALLOW_REGISTER */
+            {
+#ifdef AFS_ID_TO_NAME
+                strncpy(username_copy, username, BUFSIZ);
+                snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
+#endif /* AFS_ID_TO_NAME */
+            }
+#ifdef ALLOW_REGISTER
+        } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
+            id = 0;
+            strncpy(aclient->name, username, MAXKTCNAMELEN - 1);
+            strcpy(aclient->instance, "");
+            strncpy(aclient->cell, realm_of_user, MAXKTCREALMLEN - 1);
+            if (status = ktc_SetToken(aserver, atoken, aclient, 0))
+                return status;
+
+            /*                                    
+             * In case you're wondering, we don't need to change the
+             * filename here because we're still connecting to the
+             * same cell -- we're just using a different authentication
+             * level
+             */
+
+            if (status = pr_Initialize(1L, confname, aserver->cell, 0))
+                return status;
+            if (status = pr_CreateUser(username, &id))
+                return status;
+#ifdef AFS_ID_TO_NAME
+            strncpy(username_copy, username, BUFSIZ);
+            snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
+#endif /* AFS_ID_TO_NAME */
+        }
+    }
+#endif /* ALLOW_REGISTER */
+    return status;
+}
+
+
 int
 KFW_AFS_klog(
     krb5_context alt_ctx,
@@ -2400,7 +2559,6 @@ KFW_AFS_klog(
     krb5_creds * k5creds = 0;
     krb5_error_code code;
     krb5_principal client_principal = 0;
-    char * cname = 0, *sname = 0;
     int i, retry = 0;
 
     CurrentState = 0;
@@ -2425,10 +2583,10 @@ KFW_AFS_klog(
     memset(ServiceName, '\0', sizeof(ServiceName));
     memset(realm_of_user, '\0', sizeof(realm_of_user));
     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
-       if (cell && cell[0])
-               strcpy(Dmycell, cell);
-       else
-               memset(Dmycell, '\0', sizeof(Dmycell));
+    if (cell && cell[0])
+        strcpy(Dmycell, cell);
+    else
+        memset(Dmycell, '\0', sizeof(Dmycell));
 
     // NULL or empty cell returns information on local cell
     if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
@@ -2454,13 +2612,21 @@ KFW_AFS_klog(
     memset((char *)&increds, 0, sizeof(increds));
 
     code = pkrb5_cc_get_principal(ctx, cc, &client_principal);
-       if (code) {
+    if (code) {
         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) 
         {
             OutputDebugString("Principal Not Found for ccache\n");
         }
         goto skip_krb5_init;
     }
+
+    if ( strchr(krb5_princ_component(ctx,client_principal,0),'.') != NULL )
+    {
+        OutputDebugString("Illegal Principal name contains dot in first component\n");
+        rc = KRB5KRB_ERR_GENERIC;
+        goto cleanup;
+    }
+
     i = krb5_princ_realm(ctx, client_principal)->length;
     if (i > REALM_SZ-1) 
         i = REALM_SZ-1;
@@ -2479,7 +2645,7 @@ KFW_AFS_klog(
 #else
     goto cleanup;
 #endif
-    strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig));
+    strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig));
 
     if (strlen(service) == 0)
         strcpy(ServiceName, "afs");
@@ -2519,6 +2685,7 @@ KFW_AFS_klog(
 
 
         if ( IsDebuggerPresent() ) {
+            char * cname, *sname;
             pkrb5_unparse_name(ctx, increds.client, &cname);
             pkrb5_unparse_name(ctx, increds.server, &sname);
             OutputDebugString("Getting tickets for \"");
@@ -2526,7 +2693,8 @@ KFW_AFS_klog(
             OutputDebugString("\" and service \"");
             OutputDebugString(sname);
             OutputDebugString("\"\n");
-            cname = sname = 0;
+            pkrb5_free_unparsed_name(ctx,cname);
+            pkrb5_free_unparsed_name(ctx,sname);
         }
 
         code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds);
@@ -2554,7 +2722,6 @@ KFW_AFS_klog(
                 OutputDebugString("\"\n");
                 pkrb5_free_unparsed_name(ctx,cname);
                 pkrb5_free_unparsed_name(ctx,sname);
-                cname = sname = 0;
             }
 
             if (!code)
@@ -2588,7 +2755,6 @@ KFW_AFS_klog(
                 OutputDebugString("\"\n");
                 pkrb5_free_unparsed_name(ctx,cname);
                 pkrb5_free_unparsed_name(ctx,sname);
-                cname = sname = 0;
             }
 
             if (!code)
@@ -2619,7 +2785,6 @@ KFW_AFS_klog(
                     OutputDebugString("\"\n");
                     pkrb5_free_unparsed_name(ctx,cname);
                     pkrb5_free_unparsed_name(ctx,sname);
-                    cname = sname = 0;
                 }
 
                 if (!code)
@@ -2641,7 +2806,8 @@ KFW_AFS_klog(
          * No need to perform a krb524 translation which is 
          * commented out in the code below
          */
-        if (k5creds->ticket.length > MAXKTCTICKETLEN)
+        if (KFW_use_krb524() ||
+            k5creds->ticket.length > MAXKTCTICKETLEN)
             goto try_krb524d;
 
         memset(&aserver, '\0', sizeof(aserver));
@@ -2706,14 +2872,17 @@ KFW_AFS_klog(
             p[len] = '\0';
         }
 
+        ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+                         &aclient, &aserver, &atoken);
+
         if ( smbname ) {
-            strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN);
-            aclient.smbname[MAXRANDOMNAMELEN-1] = '\0';
+            strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
+            aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
         } else {
             aclient.smbname[0] = '\0';
         }
 
-        rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
+        rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
         if (!rc)
             goto cleanup;   /* We have successfully inserted the token */
 
@@ -2824,14 +2993,17 @@ KFW_AFS_klog(
 
     strcpy(aclient.cell, CellName);
 
+    ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
+                      &aclient, &aserver, &atoken);
+
     if ( smbname ) {
-        strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN);
-        aclient.smbname[MAXRANDOMNAMELEN-1] = '\0';
+        strncpy(aclient.smbname, smbname, sizeof(aclient.smbname));
+        aclient.smbname[sizeof(aclient.smbname)-1] = '\0';
     } else {
         aclient.smbname[0] = '\0';
     }
 
-    if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0))
+    if (rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0)))
     {
         KFW_AFS_error(rc, "ktc_SetToken()");
         code = rc;
@@ -2839,10 +3011,6 @@ KFW_AFS_klog(
     }
 
   cleanup:
-    if (cname)
-        pkrb5_free_unparsed_name(ctx,cname);
-    if (sname)
-        pkrb5_free_unparsed_name(ctx,sname);
     if (client_principal)
         pkrb5_free_principal(ctx,client_principal);
     /* increds.client == client_principal */
@@ -2860,28 +3028,20 @@ KFW_AFS_klog(
 /* afs_realm_of_cell():               */
 /**************************************/
 static char *
-afs_realm_of_cell(struct afsconf_cell *cellconfig)
+afs_realm_of_cell(krb5_context ctx, struct afsconf_cell *cellconfig)
 {
     static char krbrlm[REALM_SZ+1]="";
-    krb5_context  ctx = 0;
     char ** realmlist=NULL;
     krb5_error_code r;
 
     if (!cellconfig)
         return 0;
 
-    if (!pkrb5_init_context)
-        return 0;
-
-    r = pkrb5_init_context(&ctx); 
-    if ( !r )
-        r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
+    r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
     if ( !r && realmlist && realmlist[0] ) {
         strcpy(krbrlm, realmlist[0]);
         pkrb5_free_host_realm(ctx, realmlist);
     }
-    if (ctx)
-        pkrb5_free_context(ctx);
 
     if ( !krbrlm[0] )
     {
@@ -3126,7 +3286,14 @@ BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
     char   password[PROBE_PASSWORD_LEN+1];
     BOOL serverReachable = 0;
 
-    realm = afs_realm_of_cell(cellconfig);  // do not free
+    if (!pkrb5_init_context)
+        return 0;
+
+    code = pkrb5_init_context(&ctx);
+    if (code) goto cleanup;
+
+
+    realm = afs_realm_of_cell(ctx, cellconfig);  // do not free
 
     code = pkrb5_build_principal(ctx, &principal, strlen(realm),
                                   realm, PROBE_USERNAME, NULL, NULL);