1/* 2 * Copyright (c) 1999 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * macnc_options.c 26 * - handle dhcp/bootp options specific to the macNC 27 */ 28 29/* 30 * Modification History: 31 * 32 * December 15, 1997 Dieter Siegmund (dieter@apple) 33 * - created 34 * November 19, 1999 Dieter Siegmund (dieter@apple) 35 * - converted to regular C 36 */ 37#import <unistd.h> 38#import <stdlib.h> 39#import <stdio.h> 40#import <sys/types.h> 41#import <netinet/in.h> 42#import <arpa/inet.h> 43#import <string.h> 44#import "rfc_options.h" 45#import "macnc_options.h" 46 47typedef struct { 48 macNCtype_t type; 49 dhcptype_info_t info; 50} macNCtype_info_t; 51 52static const macNCtype_info_t macNCtype_info_table[] = { 53 { macNCtype_pstring_e, { 1, dhcptype_none_e, "PString" } }, 54 { macNCtype_afp_path_e, { 0, dhcptype_none_e, "AFP path" } }, 55 { macNCtype_afp_password_e, { 8, dhcptype_none_e, "AFP password" } }, 56}; 57 58static const int macNCtype_info_size = sizeof(macNCtype_info_table) 59 / sizeof(macNCtype_info_t); 60 61typedef struct { 62 macNCtag_t tag; 63 dhcptag_info_t info; 64} macNCtag_info_t; 65 66static const macNCtag_info_t macNCtag_info_table[] = { 67 { macNCtag_client_version_e, {dhcptype_uint32_e, "macNC_client_version" } }, 68 { macNCtag_client_info_e, { dhcptype_opaque_e, "macNC_client_info" } }, 69 { macNCtag_server_version_e, { dhcptype_uint32_e, "macNC_server_version" } }, 70 { macNCtag_server_info_e, { dhcptype_opaque_e, "macNC_server_info" } }, 71 { macNCtag_user_name_e, { dhcptype_string_e, "macNC_user_name" } }, 72 { macNCtag_password_e, { macNCtype_afp_password_e, "macNC_password" } }, 73 { macNCtag_shared_system_file_e, 74 { macNCtype_afp_path_e, "macNC_shared_system_file" } }, 75 { macNCtag_private_system_file_e, 76 { macNCtype_afp_path_e, "macNC_private_system_file" } }, 77 { macNCtag_page_file_e, 78 { macNCtype_afp_path_e, "macNC_page_file" } }, 79 { macNCtag_MacOS_machine_name_e, 80 { dhcptype_string_e, "macNC_MacOS_machine_name" } }, 81 { macNCtag_shared_system_shadow_file_e, 82 { macNCtype_afp_path_e, "macNC_shared_system_shadow_file" } }, 83 { macNCtag_private_system_shadow_file_e, 84 { macNCtype_afp_path_e, "macNC_private_system_shadow_file" } }, 85}; 86 87static int macNCtag_info_size = sizeof(macNCtag_info_table) 88 / sizeof(macNCtag_info_t); 89 90static const dhcptype_info_t * 91macNCtype_info(int type) 92{ 93 int i; 94 const dhcptype_info_t * t; 95 96 for (i = 0; i < macNCtype_info_size; i++) { 97 if (type == macNCtype_info_table[i].type) 98 return (&macNCtype_info_table[i].info); 99 } 100 t = dhcptype_info(type); 101 if (t) 102 return (t); 103 return (NULL); 104} 105 106static const dhcptag_info_t * 107macNCtag_info(int tag) 108{ 109 int i; 110 const dhcptag_info_t * t; 111 112 for (i = 0; i < macNCtag_info_size; i++) { 113 if (tag == macNCtag_info_table[i].tag) 114 return (&macNCtag_info_table[i].info); 115 } 116 t = dhcptag_info(tag); 117 if (t) 118 return (t); 119 return (NULL); 120} 121 122boolean_t 123macNCopt_str_to_type(const char * str, 124 int type, void * buf, int * len_p, 125 dhcpo_err_str_t * err) 126{ 127 const dhcptype_info_t * type_info = macNCtype_info(type); 128 129 if (err) 130 err->str[0] = '\0'; 131 132 switch (type) { 133 case macNCtype_afp_password_e: { 134 int len = strlen(str); 135 if (*len_p < AFP_PASSWORD_LEN) { 136 if (err) 137 snprintf(err->str, sizeof(err->str), 138 "%s: buffer too small (%d < %d)", 139 type_info->name, *len_p, AFP_PASSWORD_LEN); 140 return (FALSE); 141 } 142 if (len > AFP_PASSWORD_LEN) { 143 if (err) 144 snprintf(err->str, sizeof(err->str), 145 "%s: string too large (%d > %d)", 146 type_info->name, len, AFP_PASSWORD_LEN); 147 return (FALSE); 148 } 149 *len_p = AFP_PASSWORD_LEN; 150 bzero(buf, AFP_PASSWORD_LEN); 151 strncpy((char *)buf, str, len); 152 } 153 break; 154 case macNCtype_pstring_e: { 155 int len = strlen(str); 156 if (*len_p < (len + 1)) { 157 if (err) 158 snprintf(err->str, sizeof(err->str), 159 "%s: buffer too small (%d < %d)", 160 type_info->name, *len_p, len + 1); 161 return (FALSE); 162 } 163 ((u_char *)buf)[0] = len; /* string length */ 164 bcopy(str, buf + 1, len); 165 *len_p = len + 1; 166 } 167 break; 168 case macNCtype_afp_path_e: 169 if (err) 170 snprintf(err->str, sizeof(err->str), 171 "%s: not supported", type_info->name); 172 return (FALSE); 173 break; 174 default: 175 return (dhcptype_from_str(str, type, buf, len_p, err)); 176 break; 177 } 178 return (TRUE); 179} 180 181static void 182S_replace_separators(u_char * buf, int len, u_char sep, u_char new_sep) 183{ 184 int i; 185 186 for (i = 0; i < len; i++) { 187 if (buf[i] == sep) 188 buf[i] = new_sep; 189 } 190 return; 191} 192 193boolean_t 194macNCopt_encodeAFPPath(struct in_addr iaddr, uint16_t port, 195 const char * volname, uint32_t dirID, 196 uint8_t pathtype, const char * pathname, 197 char separator, void * buf, 198 int * len_p, dhcpo_err_str_t * err) 199{ 200 void * buf_p = buf; 201 int l; 202 203 l = strlen(volname) + strlen(pathname); 204 if (l > AFP_PATH_LIMIT) { 205 if (err) 206 snprintf(err->str, sizeof(err->str), 207 "volume/path name length %d > %d-byte limit", l, 208 AFP_PATH_LIMIT); 209 return (FALSE); 210 } 211 212 if ((l + AFP_PATH_OVERHEAD) > *len_p) { 213 if (err) 214 snprintf(err->str, sizeof(err->str), 215 "buffer too small: %d > %d", l + AFP_PATH_OVERHEAD, 216 *len_p); 217 return (FALSE); 218 } 219 *len_p = l + AFP_PATH_OVERHEAD; /* option len */ 220 221 *((struct in_addr *)buf_p) = iaddr; /* ip */ 222 buf_p += sizeof(iaddr); 223 224 *((u_short *)buf_p) = port; /* port */ 225 buf_p += sizeof(port); 226 227 l = strlen(volname); /* VolName */ 228 *((u_char *)buf_p) = l; 229 buf_p++; 230 if (l) 231 bcopy(volname, (u_char *)buf_p, l); 232 buf_p += l; 233 234 *((uint32_t *)buf_p) = dirID; /* DirID */ 235 buf_p += sizeof(dirID); 236 237 *((uint8_t *)buf_p) = pathtype; /* AFPPathType */ 238 buf_p += sizeof(pathtype); 239 240 l = strlen(pathname); /* PathName */ 241 *((uint8_t *)buf_p) = l; 242 buf_p++; 243 if (l) { 244 bcopy(pathname, (u_char *)buf_p, l); 245 S_replace_separators(buf_p, l, separator, AFP_PATH_SEPARATOR); 246 } 247 248 return (TRUE); 249} 250 251static void 252print_pstring(const uint8_t * option) 253 254{ 255 int i; 256 int len = option[0]; 257 258 for (i = 0; i < len; i++) { 259 char ch = option[1 + i]; 260 printf("%c", ch ? ch : '.'); 261 } 262} 263 264static void 265macNC_print_type(dhcptype_t type, void * opt, int option_len) 266{ 267 int offset; 268 uint8_t * option = opt; 269 270 switch (type) { 271 case macNCtype_afp_password_e: 272 if (option_len != AFP_PASSWORD_LEN) 273 printf("bad password field\n"); 274 else { 275 char buf[9]; 276 strncpy(buf, (char *)opt, AFP_PASSWORD_LEN); 277 buf[8] = '\0'; 278 printf("%s", buf); 279 } 280 break; 281 case macNCtype_afp_path_e: 282 offset = 0; 283 printf("("); 284 285 dhcptype_print(dhcptype_ip_e, option, option_len); 286 offset += 4; 287 288 printf(", "); 289 dhcptype_print(dhcptype_uint16_e, option + offset, option_len); 290 offset += 2; 291 292 printf(", "); 293 print_pstring(option + offset); 294 offset += option[offset] + 1; 295 296 printf(", "); 297 dhcptype_print(dhcptype_uint32_e, option + offset, option_len); 298 offset += 4; 299 300 printf(", "); 301 dhcptype_print(dhcptype_uint8_e, option + offset, option_len); 302 offset += 1; 303 304 printf(", "); 305 print_pstring(option + offset); 306 printf(")"); 307 break; 308 309 case macNCtype_pstring_e: { 310 print_pstring(option); 311 break; 312 } 313 default: 314 dhcptype_print(type, option, option_len); 315 break; 316 } 317 return; 318} 319 320boolean_t 321macNC_print_option(void * vopt) 322{ 323 u_char * opt = vopt; 324 u_char tag = opt[TAG_OFFSET]; 325 u_char option_len = opt[LEN_OFFSET]; 326 u_char * option = opt + OPTION_OFFSET; 327 const dhcptag_info_t * entry; 328 329 entry = macNCtag_info(tag); 330 if (entry == NULL) 331 return (FALSE); 332 { 333 const dhcptype_info_t * type = macNCtype_info(entry->type); 334 335 if (type == NULL) { 336 printf("unknown type %d\n", entry->type); 337 return (FALSE); 338 } 339 printf("%s (%s): ", entry->name, type->name); 340 if (tag == dhcptag_dhcp_message_type_e) 341 printf("%s ", dhcp_msgtype_names(*option)); 342 macNC_print_type(entry->type, option, option_len); 343 printf("\n"); 344 } 345 return (TRUE); 346} 347 348void 349macNCopt_print(dhcpol_t * list) 350{ 351 int i; 352 353 printf("Options count is %d\n", dhcpol_count(list)); 354 for (i = 0; i < dhcpol_count(list); i++) { 355 unsigned char * option = dhcpol_element(list, i); 356 if (macNC_print_option(option) == FALSE) 357 printf("undefined tag %d len %d\n", option[TAG_OFFSET], 358 option[LEN_OFFSET]); 359 } 360} 361 362#ifdef TEST_MACNC_OPTIONS 363 364/** 365 ** 366 ** Testing 1 2 3 367 ** 368 **/ 369u_char test[] = 370{ 371 dhcptag_subnet_mask_e, 372 4, 373 255, 255, 252, 0, 374 375 dhcptag_router_e, 376 12, 377 17, 202, 40, 1, 378 17, 202, 41, 1, 379 17, 202, 42, 1, 380 381 dhcptag_domain_name_server_e, 382 4, 383 17, 128, 100, 12, 384 385 dhcptag_host_name_e, 386 7, 387 's', 'i', 'e', 'g', 'd', 'i', '7', 388 389 dhcptag_pad_e, 390 391 dhcptag_all_subnets_local_e, 392 1, 393 0, 394 395 dhcptag_vendor_specific_e, 396 24, 397 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', 398 234, 212, 0, 1, 2, 3, 4, 5, 6, 7, 399 400 macNCtag_user_name_e, 401 10, 402 'M', 'a', 'c', 'N', 'C', ' ', '#', ' ', '1', '9', 403 404 macNCtag_shared_system_file_e, 405 29, 406 17, 202, 40, 191, 407 0x20, 0x00, 408 4, 'a', 'b', 'c', 'd', 409 0, 0, 0, 0, 410 2, 411 12, 0, 'e', 0, 'f', 0, 'g', 'h', 'i', 0, 'j', 'k', 'l', 412 413 dhcptag_end_e, 414}; 415 416#if 0 417u_char test[] = { 4180x01, 0x04, 0xff, 0x00, 0x00, 0x00, 0x03, 0x04, 0x0f, 0x03, 0x03, 0x09, 0x06, 4190x04, 0x0f, 0x03, 0x03, 0x09, 0xe8, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30, 4200xed, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30, 0xe9, 0x09, 0x08, 0x74, 0x65, 4210x73, 0x74, 0x69, 0x6e, 0x67, 0x32, 0xea, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06, 4220x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37, 4230xeb, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 4240x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37, 0xec, 0x18, 0x0f, 0x03, 0x03, 0x05, 4250x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 4260x33, 0x2e, 0x31, 0x37, 0xff, 427}; 428#endif 429 430int 431main() 432{ 433 dhcpo_err_str_t err; 434 dhcpol_t list; 435 436 dhcpol_init(&list); 437 if (dhcpol_parse_buffer(&list, test, sizeof(test), &err) == FALSE) { 438 printf("parse test failed, %s\n", err.str); 439 exit(1); 440 } 441 macNCopt_print(&list); 442 exit(0); 443#if 0 444 { 445 struct in_addr iaddr; 446 int i = sizeof(iaddr); 447 448 if ([options str:"17.202.42.129" ToType:dhcptype_ip_e 449 Buffer:(void *)&iaddr Length:&i] == FALSE) { 450 printf("conversion failed %s\n", [options errString]); 451 } 452 else { 453 printf("ip address should be 17.202.42.129: "); 454 [options printType:dhcptype_ip_e Size:i Option:(void *)&iaddr 455 Length:i]; 456 printf("\n"); 457 } 458 } 459 { 460 unsigned char buf[32] = "Mac NC #33"; 461 unsigned char buf2[34]; 462 int len = sizeof(buf2); 463 464 if ([options str:buf ToType:macNCtype_pstring_e Buffer:buf2 465 Length:&len] == FALSE) { 466 printf("conversion failed %s\n", [options errString]); 467 } 468 else { 469 printf("macNCtype string should be %s:", buf); 470 [options printType:macNCtype_pstring_e Size:0 Option:buf2 471 Length:len]; 472 printf("\n"); 473 } 474 } 475 { 476 struct in_addr iaddr[10]; 477 int l = sizeof(iaddr); 478 u_char * strList[] = { "17.202.40.1", "17.202.41.1", "17.202.42.1", 479 "17.202.43.1" }; 480 int num = sizeof(strList) / sizeof(*strList); 481 482 if ([options strList:strList Number:num Tag:dhcptag_router_e 483 Buffer:(void *)iaddr Length:&l] == FALSE) { 484 printf("conversion failed %s\n", [options errString]); 485 } 486 else { 487 [options printType:dhcptype_ip_mult_e Size:4 Option:(void *)iaddr 488 Length:l]; 489 printf("\n"); 490 } 491 } 492 { 493 u_char buf[100]; 494 u_char * strList[] = { "17.86.91.2", "0x100", "0", "greatVolumeName", 495 "/spectacular/path/name/eh" }; 496 int l = sizeof(buf); 497 int num = sizeof(strList) / sizeof(*strList); 498 499 if ([macNCOptions strList:strList Number:num 500 Tag:macNCtag_system_path_shared_e Buffer:(void *)buf Length:&l 501 ErrorString:[options errString]] == FALSE) { 502 printf("conversion failed %s\n", [options errString]); 503 } 504 else { 505 printf("conversion OK\n"); 506 [options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf 507 Length:l]; 508 printf("\n"); 509 } 510 } 511 { 512 u_char buf[100]; 513 int l = sizeof(buf); 514 struct in_addr iaddr; 515 516 iaddr.s_addr = inet_addr("17.202.101.100"); 517 if ([macNCOptions encodeAFPPath 518 : iaddr 519 : 0x1234 520 : "volumeName" 521 : AFP_DIRID_NULL 522 : AFP_PATHTYPE_LONG 523 : "this:is:the:path" 524 : ':' 525 Into: (void *)buf 526 Length: &l 527 ErrorString: [options errString]] == FALSE) { 528 printf("conversion path failed %s\n", [options errString]); 529 } 530 else { 531 printf("conversion OK\n"); 532 [options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf 533 Length:l]; 534 printf("\n"); 535 } 536 537 } 538 [options free]; 539 options = nil; 540 { 541 unsigned char buf[300]; 542 int len = sizeof(buf); 543 id o = [[macNCOptions alloc] initWithBuffer:(void *)buf Size:len]; 544 545 if (o == nil) { 546 printf("initWithBuffer failed\n"); 547 } 548 else { 549 if ([o addOption:macNCtag_user_name_e FromString:"Mac NC # 22"] 550 == FALSE 551 || 552 [o addOption:dhcptag_subnet_mask_e FromString:"255.255.255.0"] 553 == FALSE 554 || 555 [o addOption:dhcptag_end_e Length:0 Data:0] == FALSE 556 ) { 557 printf("%s", [o errString]); 558 } 559 else { 560 [o parse]; 561 [o print]; 562 } 563 } 564 } 565 566#endif 567 568 exit(0); 569} 570#endif /* TEST_MACNC_OPTIONS */ 571 572