1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * lib/krb5/krb/unparse.c 8 * 9 * Copyright 1990, 2008 by the Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 * 32 * krb5_unparse_name() routine 33 * 34 * Rewritten by Theodore Ts'o to properly unparse principal names 35 * which have the component or realm separator as part of one of their 36 * components. 37 */ 38 39 40 #include "k5-int.h" 41 #ifndef _KERNEL 42 #include <stdio.h> 43 #endif 44 45 /* 46 * SUNW17PACresync / Solaris Kerberos 47 * This realloc works for both Solaris kernel and user space. 48 */ 49 void * 50 krb5int_realloc( 51 void *oldp, 52 size_t new_size, 53 size_t old_size) 54 { 55 #ifdef _KERNEL 56 char *newp = MALLOC(new_size); 57 58 bcopy(oldp, newp, old_size < new_size ? old_size : new_size); 59 FREE(oldp, old_size); 60 61 return (newp); 62 #else 63 return (realloc(oldp, new_size)); 64 #endif 65 } 66 67 /* 68 * converts the multi-part principal format used in the protocols to a 69 * single-string representation of the name. 70 * 71 * The name returned is in allocated storage and should be freed by 72 * the caller when finished. 73 * 74 * Conventions: / is used to separate components; @ is used to 75 * separate the realm from the rest of the name. If '/', '@', or '\0' 76 * appear in any the component, they will be representing using 77 * backslash encoding. ("\/", "\@", or '\0', respectively) 78 * 79 * returns error 80 * KRB_PARSE_MALFORMED principal is invalid (does not contain 81 * at least 2 components) 82 * also returns system errors 83 * ENOMEM unable to allocate memory for string 84 */ 85 86 #define REALM_SEP '@' 87 #define COMPONENT_SEP '/' 88 89 static int 90 component_length_quoted(const krb5_data *src, int flags) 91 { 92 const char *cp = src->data; 93 int length = src->length; 94 int j; 95 int size = length; 96 97 if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) { 98 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) && 99 !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT); 100 101 for (j = 0; j < length; j++,cp++) 102 if ((!no_realm && *cp == REALM_SEP) || 103 *cp == COMPONENT_SEP || 104 *cp == '\0' || *cp == '\\' || *cp == '\t' || 105 *cp == '\n' || *cp == '\b') 106 size++; 107 } 108 109 return size; 110 } 111 112 static int 113 copy_component_quoting(char *dest, const krb5_data *src, int flags) 114 { 115 int j; 116 const char *cp = src->data; 117 char *q = dest; 118 int length = src->length; 119 120 if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) { 121 (void) memcpy(dest, src->data, src->length); 122 return src->length; 123 } 124 125 for (j=0; j < length; j++,cp++) { 126 int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) && 127 !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT); 128 129 switch (*cp) { 130 case REALM_SEP: 131 if (no_realm) { 132 *q++ = *cp; 133 break; 134 } 135 /*LINTED*/ 136 case COMPONENT_SEP: 137 case '\\': 138 *q++ = '\\'; 139 *q++ = *cp; 140 break; 141 case '\t': 142 *q++ = '\\'; 143 *q++ = 't'; 144 break; 145 case '\n': 146 *q++ = '\\'; 147 *q++ = 'n'; 148 break; 149 case '\b': 150 *q++ = '\\'; 151 *q++ = 'b'; 152 break; 153 #if 0 154 /* Heimdal escapes spaces in principal names upon unparsing */ 155 case ' ': 156 *q++ = '\\'; 157 *q++ = ' '; 158 break; 159 #endif 160 case '\0': 161 *q++ = '\\'; 162 *q++ = '0'; 163 break; 164 default: 165 *q++ = *cp; 166 } 167 } 168 /*LINTED*/ 169 return q - dest; 170 } 171 172 static krb5_error_code 173 /*LINTED*/ 174 k5_unparse_name(krb5_context context, krb5_const_principal principal, 175 int flags, char **name, unsigned int *size) 176 { 177 #if 0 178 /* SUNW17PACresync - lint - cp/length not used */ 179 char *cp; 180 int length; 181 #endif 182 char *q; 183 int i; 184 krb5_int32 nelem; 185 unsigned int totalsize = 0; 186 #ifndef _KERNEL 187 /* SUNW17PACresync - princ in kernel will always have realm */ 188 char *default_realm = NULL; 189 #endif 190 krb5_error_code ret = 0; 191 192 if (!principal || !name) 193 return KRB5_PARSE_MALFORMED; 194 195 #ifndef _KERNEL 196 if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) { 197 /* omit realm if local realm */ 198 krb5_principal_data p; 199 200 ret = krb5_get_default_realm(context, &default_realm); 201 if (ret != 0) 202 goto cleanup; 203 204 krb5_princ_realm(context, &p)->length = strlen(default_realm); 205 krb5_princ_realm(context, &p)->data = default_realm; 206 207 if (krb5_realm_compare(context, &p, principal)) 208 flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM; 209 } 210 #endif 211 if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { 212 totalsize += component_length_quoted(krb5_princ_realm(context, 213 principal), 214 flags); 215 totalsize++; /* This is for the separator */ 216 } 217 218 nelem = krb5_princ_size(context, principal); 219 for (i = 0; i < (int) nelem; i++) { 220 #if 0 221 /* SUNW17PACresync - lint - cp not used */ 222 cp = krb5_princ_component(context, principal, i)->data; 223 #endif 224 totalsize += component_length_quoted(krb5_princ_component(context, principal, i), flags); 225 totalsize++; /* This is for the separator */ 226 } 227 if (nelem == 0) 228 totalsize++; 229 230 /* 231 * Allocate space for the ascii string; if space has been 232 * provided, use it, realloc'ing it if necessary. 233 * 234 * We need only n-1 seperators for n components, but we need 235 * an extra byte for the NUL at the end. 236 */ 237 238 if (size) { 239 if (*name && (*size < totalsize)) { 240 /* SUNW17PACresync - works for both kernel&user */ 241 *name = krb5int_realloc(*name, totalsize, *size); 242 } else { 243 *name = MALLOC(totalsize); 244 } 245 *size = totalsize; 246 } else { 247 *name = MALLOC(totalsize); 248 } 249 250 if (!*name) { 251 ret = ENOMEM; 252 goto cleanup; 253 } 254 255 q = *name; 256 257 for (i = 0; i < (int) nelem; i++) { 258 #if 0 259 /* SUNW17PACresync - lint - cp/length not used */ 260 cp = krb5_princ_component(context, principal, i)->data; 261 length = krb5_princ_component(context, principal, i)->length; 262 #endif 263 q += copy_component_quoting(q, 264 krb5_princ_component(context, 265 principal, 266 i), 267 flags); 268 *q++ = COMPONENT_SEP; 269 } 270 271 if (i > 0) 272 q--; /* Back up last component separator */ 273 if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) { 274 *q++ = REALM_SEP; 275 q += copy_component_quoting(q, krb5_princ_realm(context, principal), flags); 276 } 277 *q++ = '\0'; 278 279 cleanup: 280 #ifndef _KERNEL 281 if (default_realm != NULL) 282 krb5_free_default_realm(context, default_realm); 283 #endif 284 return ret; 285 } 286 287 krb5_error_code KRB5_CALLCONV 288 krb5_unparse_name(krb5_context context, krb5_const_principal principal, register char **name) 289 { 290 if (name != NULL) /* name == NULL will return error from _ext */ 291 *name = NULL; 292 293 return k5_unparse_name(context, principal, 0, name, NULL); 294 } 295 296 krb5_error_code KRB5_CALLCONV 297 krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal, 298 char **name, unsigned int *size) 299 { 300 return k5_unparse_name(context, principal, 0, name, size); 301 } 302 303 krb5_error_code KRB5_CALLCONV 304 krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal, 305 int flags, char **name) 306 { 307 if (name != NULL) 308 *name = NULL; 309 return k5_unparse_name(context, principal, flags, name, NULL); 310 } 311 312 krb5_error_code KRB5_CALLCONV 313 krb5_unparse_name_flags_ext(krb5_context context, krb5_const_principal principal, 314 int flags, char **name, unsigned int *size) 315 { 316 return k5_unparse_name(context, principal, flags, name, size); 317 } 318 319