When user_realm is used by PAM, do likewise in kinit.
When PAM is configured to use a user_realm that is different from the default realm, do likewise in kinit with bare user names or the default principal computed from the login name. Similarly, when using a keytab, if no realm is specified find the most suitable match in the keytab file.
This commit is contained in:
		 Viktor Dukhovni
					Viktor Dukhovni
				
			
				
					committed by
					
						 Viktor Dukhovni
						Viktor Dukhovni
					
				
			
			
				
	
			
			
			 Viktor Dukhovni
						Viktor Dukhovni
					
				
			
						parent
						
							4fcad71a3a
						
					
				
				
					commit
					3f3bcc2731
				
			
							
								
								
									
										234
									
								
								kuser/kinit.c
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								kuser/kinit.c
									
									
									
									
									
								
							| @@ -63,6 +63,7 @@ static int switch_cache_flags = 1; | ||||
| struct getarg_strings etype_str; | ||||
| int use_keytab		= 0; | ||||
| char *keytab_str	= NULL; | ||||
| static krb5_keytab kt	= NULL; | ||||
| int do_afslog		= -1; | ||||
| int fcache_version; | ||||
| char *password_file	= NULL; | ||||
| @@ -361,7 +362,6 @@ get_new_tickets(krb5_context context, | ||||
|     const char *renewstr = NULL; | ||||
|     krb5_enctype *enctype = NULL; | ||||
|     krb5_ccache tempccache; | ||||
|     krb5_keytab kt = NULL; | ||||
|     krb5_init_creds_context ctx; | ||||
| #ifndef NO_NTLM | ||||
|     struct ntlm_buf ntlmkey; | ||||
| @@ -524,18 +524,9 @@ get_new_tickets(krb5_context context, | ||||
|     } | ||||
|  | ||||
|     if (use_keytab || keytab_str) { | ||||
|  | ||||
| 	if (keytab_str) | ||||
| 	    ret = krb5_kt_resolve(context, keytab_str, &kt); | ||||
| 	else | ||||
| 	    ret = krb5_kt_default(context, &kt); | ||||
| 	if (ret) | ||||
| 	    krb5_err(context, 1, ret, "resolving keytab"); | ||||
|  | ||||
| 	ret = krb5_init_creds_set_keytab(context, ctx, kt); | ||||
| 	if (ret) | ||||
| 	    krb5_err(context, 1, ret, "krb5_init_creds_set_keytab"); | ||||
|  | ||||
|     } else if (pk_user_id || ent_user_id || anonymous_flag) { | ||||
|  | ||||
|     } else if (!interactive) { | ||||
| @@ -666,8 +657,6 @@ get_new_tickets(krb5_context context, | ||||
|  | ||||
|     krb5_get_init_creds_opt_free(context, opt); | ||||
|  | ||||
|     if (kt)			 | ||||
| 	krb5_kt_close(context, kt); | ||||
|     if (enctype) | ||||
| 	free(enctype); | ||||
|  | ||||
| @@ -773,16 +762,204 @@ renew_func(void *ptr) | ||||
|     return expire / 2 + 1; | ||||
| } | ||||
|  | ||||
| static void | ||||
| parse_name_realm(krb5_context context, | ||||
| 		 const char *name, | ||||
| 		 int flags, | ||||
| 		 const char *realm, | ||||
| 		 krb5_principal *princ) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|  | ||||
|     ret = krb5_parse_name_flags_realm(context, name, flags, realm, princ); | ||||
|     if (ret) | ||||
| 	krb5_err(context, 1, ret, "krb5_parse_name_flags_realm"); | ||||
| } | ||||
|  | ||||
| static char * | ||||
| get_default_realm(krb5_context context) | ||||
| { | ||||
|     char *realm; | ||||
|     krb5_error_code ret; | ||||
|  | ||||
|     if ((ret = krb5_get_default_realm(context, &realm)) != 0) | ||||
|         krb5_err(context, 1, ret, "krb5_get_default_realm"); | ||||
|     return realm; | ||||
| } | ||||
|  | ||||
| static void | ||||
| get_default_principal(krb5_context context, krb5_principal *princ) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|  | ||||
|     if ((ret = krb5_get_default_principal(context, princ)) != 0) | ||||
| 	krb5_err(context, 1, ret, "krb5_get_default_principal"); | ||||
| } | ||||
|  | ||||
| static void | ||||
| set_princ_realm(krb5_context context, | ||||
| 		krb5_principal principal, | ||||
| 		const char *realm) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|  | ||||
|     if ((ret = krb5_principal_set_realm(context, principal, realm)) != 0) | ||||
| 	krb5_err(context, 1, ret, "krb5_principal_set_realm"); | ||||
| } | ||||
|  | ||||
| static char * | ||||
| get_user_realm(krb5_context context) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|     char *user_realm = NULL; | ||||
|  | ||||
|     /* | ||||
|      * If memory allocation fails, we don't try to use the wrong realm, | ||||
|      * that will trigger misleading error messages complicate support. | ||||
|      */ | ||||
|     krb5_appdefault_string(context, "kinit", NULL, "user_realm", "", | ||||
| 			   &user_realm); | ||||
|     if (user_realm == NULL) { | ||||
| 	ret = krb5_enomem(context); | ||||
| 	krb5_err(context, 1, ret, "krb5_appdefault_string"); | ||||
|     } | ||||
|  | ||||
|     if (*user_realm == 0) { | ||||
|     	free(user_realm); | ||||
| 	user_realm = NULL; | ||||
|     } | ||||
|  | ||||
|     return user_realm; | ||||
| } | ||||
|  | ||||
| static void | ||||
| get_princ(krb5_context context, krb5_principal *principal, const char *name) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|     krb5_principal tmp; | ||||
|     int parseflags = 0; | ||||
|     char *user_realm; | ||||
|  | ||||
|     if (name == NULL) { | ||||
| 	krb5_ccache ccache; | ||||
|  | ||||
| 	/* If credential cache provides a client principal, use that. */ | ||||
| 	if (krb5_cc_default(context, &ccache) == 0) { | ||||
| 	    ret = krb5_cc_get_principal(context, ccache, principal); | ||||
| 	    krb5_cc_close(context, ccache); | ||||
| 	    if (ret == 0) | ||||
| 		return; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     user_realm = get_user_realm(context); | ||||
|  | ||||
|     if (name) { | ||||
| 	if (canonicalize_flag || enterprise_flag) | ||||
| 	    parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; | ||||
|  | ||||
| 	parse_name_realm(context, name, parseflags, user_realm, &tmp); | ||||
|  | ||||
| 	if (user_realm && krb5_principal_get_num_comp(context, tmp) > 1) { | ||||
| 	    /* Principal is instance qualified, reparse with default realm. */ | ||||
| 	    krb5_free_principal(context, tmp); | ||||
| 	    parse_name_realm(context, name, parseflags, NULL, principal); | ||||
| 	} else { | ||||
| 	    *principal = tmp; | ||||
| 	} | ||||
|     } else { | ||||
| 	get_default_principal(context, principal); | ||||
| 	if (user_realm) | ||||
| 	    set_princ_realm(context, *principal, user_realm); | ||||
|     } | ||||
|  | ||||
|     if (user_realm) | ||||
| 	free(user_realm); | ||||
| } | ||||
|  | ||||
| static void | ||||
| get_princ_kt(krb5_context context, | ||||
| 	     krb5_principal *principal, | ||||
| 	     char *name) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|     krb5_principal tmp; | ||||
|     krb5_ccache ccache; | ||||
|     krb5_kt_cursor cursor; | ||||
|     krb5_keytab_entry entry; | ||||
|     int parseflags = 0; | ||||
|     char *def_realm; | ||||
|  | ||||
|     if (name == NULL) { | ||||
| 	/* | ||||
| 	 * If the credential cache exists and specifies a client principal, | ||||
| 	 * use that. | ||||
| 	 */ | ||||
| 	if (krb5_cc_default(context, &ccache) == 0) { | ||||
| 	    ret = krb5_cc_get_principal(context, ccache, principal); | ||||
| 	    krb5_cc_close(context, ccache); | ||||
| 	    if (ret == 0) | ||||
| 		return; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (name) { | ||||
| 	/* If the principal specifies an explicit realm, just use that. */ | ||||
| 	parseflags |= KRB5_PRINCIPAL_PARSE_NO_DEF_REALM; | ||||
| 	parse_name_realm(context, name, parseflags, NULL, &tmp); | ||||
| 	if (krb5_principal_get_realm(context, tmp) != NULL) { | ||||
| 	    *principal = tmp; | ||||
| 	    return; | ||||
| 	} | ||||
|     } else { | ||||
| 	/* Otherwise, search keytab for bare name of the default principal. */ | ||||
| 	get_default_principal(context, &tmp); | ||||
| 	set_princ_realm(context, tmp, NULL); | ||||
|     } | ||||
|  | ||||
|     def_realm = get_default_realm(context); | ||||
|  | ||||
|     ret = krb5_kt_start_seq_get(context, kt, &cursor); | ||||
|     if (ret) | ||||
| 	krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); | ||||
|  | ||||
|     while (ret == 0 && | ||||
|            krb5_kt_next_entry(context, kt, &entry, &cursor) == 0) { | ||||
|         const char *realm; | ||||
|  | ||||
|         if (!krb5_principal_compare_any_realm(context, tmp, entry.principal)) | ||||
|             continue; | ||||
|         if (*principal && | ||||
| 	    krb5_principal_compare(context, *principal, entry.principal)) | ||||
|             continue; | ||||
|         /* The default realm takes precedence */ | ||||
|         realm = krb5_principal_get_realm(context, entry.principal); | ||||
|         if (*principal && strcmp(def_realm, realm) == 0) { | ||||
|             krb5_free_principal(context, *principal); | ||||
|             ret = krb5_copy_principal(context, entry.principal, principal); | ||||
|             break; | ||||
|         } | ||||
|         if (!*principal) | ||||
|             ret = krb5_copy_principal(context, entry.principal, principal); | ||||
|     } | ||||
|     if (ret != 0 || (ret = krb5_kt_end_seq_get(context, kt, &cursor)) != 0) | ||||
| 	krb5_err(context, 1, ret, "get_princ_kt"); | ||||
|     if (!*principal) | ||||
| 	parse_name_realm(context, name, parseflags, NULL, principal); | ||||
|  | ||||
|     krb5_free_principal(context, tmp); | ||||
|     free(def_realm); | ||||
| } | ||||
|  | ||||
| int | ||||
| main(int argc, char **argv) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|     krb5_context context; | ||||
|     krb5_ccache  ccache; | ||||
|     krb5_principal principal; | ||||
|     krb5_principal principal = NULL; | ||||
|     int optidx = 0; | ||||
|     krb5_deltat ticket_life = 0; | ||||
|     int parseflags = 0; | ||||
|  | ||||
|     setprogname(argv[0]); | ||||
|  | ||||
| @@ -810,8 +987,18 @@ main(int argc, char **argv) | ||||
|     argc -= optidx; | ||||
|     argv += optidx; | ||||
|  | ||||
|     if (canonicalize_flag || enterprise_flag) | ||||
| 	parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; | ||||
|     /* | ||||
|      * Open the keytab now, we use the keytab to determine the principal's | ||||
|      * realm when the requested principal has no realm. | ||||
|      */ | ||||
|     if (use_keytab || keytab_str) { | ||||
| 	if (keytab_str) | ||||
| 	    ret = krb5_kt_resolve(context, keytab_str, &kt); | ||||
| 	else | ||||
| 	    ret = krb5_kt_default(context, &kt); | ||||
| 	if (ret) | ||||
| 	    krb5_err(context, 1, ret, "resolving keytab"); | ||||
|     } | ||||
|  | ||||
|     if (pk_enterprise_flag) { | ||||
| 	ret = krb5_pk_enterprise_cert(context, pk_user_id, | ||||
| @@ -831,17 +1018,10 @@ main(int argc, char **argv) | ||||
| 	    krb5_err(context, 1, ret, "krb5_make_principal"); | ||||
| 	krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); | ||||
|  | ||||
|     } else if (use_keytab || keytab_str) { | ||||
| 	get_princ_kt(context, &principal, argv[0]); | ||||
|     } else { | ||||
| 	if (argv[0]) { | ||||
| 	    ret = krb5_parse_name_flags(context, argv[0], parseflags, | ||||
| 					&principal); | ||||
| 	    if (ret) | ||||
| 		krb5_err(context, 1, ret, "krb5_parse_name"); | ||||
| 	} else { | ||||
| 	    ret = krb5_get_default_principal(context, &principal); | ||||
| 	    if (ret) | ||||
| 		krb5_err(context, 1, ret, "krb5_get_default_principal"); | ||||
| 	} | ||||
| 	get_princ(context, &principal, argv[0]); | ||||
|     } | ||||
|  | ||||
|     if (fcache_version) | ||||
| @@ -969,6 +1149,8 @@ main(int argc, char **argv) | ||||
| 	ret = 0; | ||||
|     } | ||||
|     krb5_free_principal(context, principal); | ||||
|     if (kt) | ||||
| 	krb5_kt_close(context, kt); | ||||
|     krb5_free_context(context); | ||||
|     return ret; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user