1 /* 2 * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/krb5/krb/conv_princ.c 10 * 11 * Copyright 1992 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 * Build a principal from a V4 specification, or separate a V5 34 * principal into name, instance, and realm. 35 * 36 * NOTE: This is highly site specific, and is only really necessary 37 * for sites who need to convert from V4 to V5. It is used by both 38 * the KDC and the kdb5_convert program. Since its use is highly 39 * specialized, the necesary information is just going to be 40 * hard-coded in this file. 41 */ 42 43 #include <k5-int.h> 44 #include <string.h> 45 #include <ctype.h> 46 47 /* The maximum sizes for V4 aname, realm, sname, and instance +1 */ 48 /* Taken from krb.h */ 49 #define ANAME_SZ 40 50 #define REALM_SZ 40 51 #define SNAME_SZ 40 52 #define INST_SZ 40 53 54 struct krb_convert { 55 char *v4_str; 56 char *v5_str; 57 int flags; 58 }; 59 60 #define DO_REALM_CONVERSION 0x00000001 61 62 /* 63 * Kadmin doesn't do realm conversion because it's currently 64 * kadmin/REALM.NAME. It should be kadmin/kerberos.master.host, but 65 * we'll fix that in the next release. 66 */ 67 static const struct krb_convert sconv_list[] = { 68 {"kadmin", "kadmin", 0}, 69 {"rcmd", "host", DO_REALM_CONVERSION}, 70 {"discuss", "discuss", DO_REALM_CONVERSION}, 71 {"rvdsrv", "rvdsrv", DO_REALM_CONVERSION}, 72 {"sample", "sample", DO_REALM_CONVERSION}, 73 {"olc", "olc", DO_REALM_CONVERSION}, 74 {"pop", "pop", DO_REALM_CONVERSION}, 75 {"sis", "sis", DO_REALM_CONVERSION}, 76 {"rfs", "rfs", DO_REALM_CONVERSION}, 77 {"imap", "imap", DO_REALM_CONVERSION}, 78 {"ftp", "ftp", DO_REALM_CONVERSION}, 79 {"ecat", "ecat", DO_REALM_CONVERSION}, 80 {"daemon", "daemon", DO_REALM_CONVERSION}, 81 {"gnats", "gnats", DO_REALM_CONVERSION}, 82 {"moira", "moira", DO_REALM_CONVERSION}, 83 {"prms", "prms", DO_REALM_CONVERSION}, 84 {"mandarin", "mandarin", DO_REALM_CONVERSION}, 85 {"register", "register", DO_REALM_CONVERSION}, 86 {"changepw", "changepw", DO_REALM_CONVERSION}, 87 {"sms", "sms", DO_REALM_CONVERSION}, 88 {"afpserver", "afpserver", DO_REALM_CONVERSION}, 89 {"gdss", "gdss", DO_REALM_CONVERSION}, 90 {"news", "news", DO_REALM_CONVERSION}, 91 {"abs", "abs", DO_REALM_CONVERSION}, 92 {"nfs", "nfs", DO_REALM_CONVERSION}, 93 {"tftp", "tftp", DO_REALM_CONVERSION}, 94 {"zephyr", "zephyr", 0}, 95 {"http", "http", DO_REALM_CONVERSION}, 96 {"khttp", "khttp", DO_REALM_CONVERSION}, 97 {"pgpsigner", "pgpsigner", DO_REALM_CONVERSION}, 98 {"irc", "irc", DO_REALM_CONVERSION}, 99 {"mandarin-agent", "mandarin-agent", DO_REALM_CONVERSION}, 100 {"write", "write", DO_REALM_CONVERSION}, 101 {"palladium", "palladium", DO_REALM_CONVERSION}, 102 {0, 0, 0}, 103 }; 104 105 /* 106 * char *strnchr(s, c, n) 107 * char *s; 108 * char c; 109 * int n; 110 * 111 * returns a pointer to the first occurrence of character c in the 112 * string s, or a NULL pointer if c does not occur in in the string; 113 * however, at most the first n characters will be considered. 114 * 115 * This falls in the "should have been in the ANSI C library" 116 * category. :-) 117 */ 118 static char *strnchr(s, c, n) 119 register char *s, c; 120 register int n; 121 { 122 if (n < 1) 123 return 0; 124 125 while (n-- && *s) { 126 if (*s == c) 127 return s; 128 s++; 129 } 130 return 0; 131 } 132 133 134 /* XXX This calls for a new error code */ 135 #define KRB5_INVALID_PRINCIPAL KRB5_LNAME_BADFORMAT 136 137 /*ARGSUSED*/ 138 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 139 krb5_524_conv_principal(context, princ, name, inst, realm) 140 krb5_context context; 141 const krb5_principal princ; 142 char FAR *name; 143 char FAR *inst; 144 char FAR *realm; 145 { 146 const struct krb_convert *p; 147 krb5_data *compo; 148 char *c, *tmp_realm, *tmp_prealm; 149 int tmp_realm_len, retval; 150 151 *name = *inst = '\0'; 152 switch (krb5_princ_size(context, princ)) { 153 case 2: 154 /* Check if this principal is listed in the table */ 155 compo = krb5_princ_component(context, princ, 0); 156 p = sconv_list; 157 while (p->v4_str) { 158 if (strncmp(p->v5_str, compo->data, compo->length) == 0) { 159 /* 160 * It is, so set the new name now, and chop off 161 * instance's domain name if requested. 162 */ 163 if (strlen (p->v4_str) > ANAME_SZ - 1) 164 return KRB5_INVALID_PRINCIPAL; 165 strcpy(name, p->v4_str); 166 if (p->flags & DO_REALM_CONVERSION) { 167 compo = krb5_princ_component(context, princ, 1); 168 c = strnchr(compo->data, '.', compo->length); 169 if (!c || (c - compo->data) >= INST_SZ - 1) 170 return KRB5_INVALID_PRINCIPAL; 171 memcpy(inst, compo->data, c - compo->data); 172 inst[c - compo->data] = '\0'; 173 } 174 break; 175 } 176 p++; 177 } 178 /* If inst isn't set, the service isn't listed in the table, */ 179 /* so just copy it. */ 180 if (*inst == '\0') { 181 compo = krb5_princ_component(context, princ, 1); 182 if (compo->length >= INST_SZ - 1) 183 return KRB5_INVALID_PRINCIPAL; 184 memcpy(inst, compo->data, compo->length); 185 inst[compo->length] = '\0'; 186 } 187 /* fall through */ 188 /*FALLTHRU*/ 189 case 1: 190 /* name may have been set above; otherwise, just copy it */ 191 if (*name == '\0') { 192 compo = krb5_princ_component(context, princ, 0); 193 if (compo->length >= ANAME_SZ) 194 return KRB5_INVALID_PRINCIPAL; 195 memcpy(name, compo->data, compo->length); 196 name[compo->length] = '\0'; 197 } 198 break; 199 default: 200 return KRB5_INVALID_PRINCIPAL; 201 } 202 203 compo = krb5_princ_realm(context, princ); 204 205 tmp_prealm = malloc(compo->length + 1); 206 if (tmp_prealm == NULL) 207 return ENOMEM; 208 strncpy(tmp_prealm, compo->data, compo->length); 209 tmp_prealm[compo->length] = '\0'; 210 211 /* Ask for v4_realm corresponding to 212 krb5 principal realm from krb5.conf realms stanza */ 213 214 if (context->profile == 0) 215 return KRB5_CONFIG_CANTOPEN; 216 retval = profile_get_string(context->profile, "realms", 217 tmp_prealm, "v4_realm", 0, 218 &tmp_realm); 219 free(tmp_prealm); 220 if (retval) { 221 return retval; 222 } else { 223 if (tmp_realm == 0) { 224 if (compo->length > REALM_SZ - 1) 225 return KRB5_INVALID_PRINCIPAL; 226 strncpy(realm, compo->data, compo->length); 227 realm[compo->length] = '\0'; 228 } else { 229 tmp_realm_len = strlen(tmp_realm); 230 if (tmp_realm_len > REALM_SZ - 1) 231 return KRB5_INVALID_PRINCIPAL; 232 strncpy(realm, tmp_realm, tmp_realm_len); 233 realm[tmp_realm_len] = '\0'; 234 profile_release_string(tmp_realm); 235 } 236 } 237 return 0; 238 } 239 240 /*ARGSUSED*/ 241 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV 242 krb5_425_conv_principal(context, name, instance, realm, princ) 243 krb5_context context; 244 const char FAR *name; 245 const char FAR *instance; 246 const char FAR *realm; 247 krb5_principal FAR *princ; 248 { 249 const struct krb_convert *p; 250 char buf[256]; /* V4 instances are limited to 40 characters */ 251 krb5_error_code retval; 252 char **full_name = 0; 253 char *domain, *cp; 254 const char *names[5]; 255 void* iterator = NULL; 256 char** v4realms = NULL; 257 char* realm_name = NULL; 258 char* dummy_value = NULL; 259 260 /* First, convert the realm, since the v4 realm is not necessarily the same as the v5 realm 261 To do that, iterate over all the realms in the config file, looking for a matching 262 v4_realm line */ 263 names [0] = "realms"; 264 names [1] = NULL; 265 retval = profile_iterator_create (context -> profile, names, PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, &iterator); 266 while (retval == 0) { 267 retval = profile_iterator (&iterator, &realm_name, &dummy_value); 268 if ((retval == 0) && (realm_name != NULL)) { 269 names [0] = "realms"; 270 names [1] = realm_name; 271 names [2] = "v4_realm"; 272 names [3] = NULL; 273 274 retval = profile_get_values (context -> profile, names, &v4realms); 275 if ((retval == 0) && (v4realms != NULL) && (v4realms [0] != NULL) && (strcmp (v4realms [0], realm) == 0)) { 276 realm = realm_name; 277 break; 278 } else if (retval == PROF_NO_RELATION) { 279 /* If it's not found, just keep going */ 280 retval = 0; 281 } 282 } else if ((retval == 0) && (realm_name == NULL)) { 283 break; 284 } 285 if (realm_name != NULL) { 286 profile_release_string (realm_name); 287 realm_name = NULL; 288 } 289 if (dummy_value != NULL) { 290 profile_release_string (dummy_value); 291 dummy_value = NULL; 292 } 293 } 294 295 if (instance) { 296 if (instance[0] == '\0') { 297 instance = 0; 298 goto not_service; 299 } 300 p = sconv_list; 301 /*CONSTCOND*/ 302 while (TRUE) { 303 if (!p->v4_str) 304 goto not_service; 305 if (!strcmp(p->v4_str, name)) 306 break; 307 p++; 308 } 309 name = p->v5_str; 310 if ((p->flags & DO_REALM_CONVERSION) && !strchr(instance, '.')) { 311 names[0] = "realms"; 312 names[1] = realm; 313 names[2] = "v4_instance_convert"; 314 names[3] = instance; 315 names[4] = 0; 316 retval = profile_get_values(context->profile, names, &full_name); 317 if (retval == 0 && full_name && full_name[0]) { 318 instance = full_name[0]; 319 } else { 320 strncpy(buf, instance, sizeof(buf)); 321 buf[sizeof(buf) - 1] = '\0'; 322 retval = krb5_get_realm_domain(context, realm, &domain); 323 if (retval) 324 return retval; 325 if (domain) { 326 for (cp = domain; *cp; cp++) 327 if (isupper(*cp)) 328 *cp = tolower(*cp); 329 strncat(buf, ".", sizeof(buf) - 1 - strlen(buf)); 330 strncat(buf, domain, sizeof(buf) - 1 - strlen(buf)); 331 krb5_xfree(domain); 332 } 333 instance = buf; 334 } 335 } 336 } 337 338 not_service: 339 retval = krb5_build_principal(context, princ, strlen(realm), realm, name, 340 instance, 0); 341 profile_iterator_free (&iterator); 342 profile_free_list(full_name); 343 profile_free_list(v4realms); 344 profile_release_string (realm_name); 345 profile_release_string (dummy_value); 346 return retval; 347 } 348