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 = (int)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 = (int)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 default: 174 return (dhcptype_from_str(str, type, buf, len_p, err)); 175 } 176 return (TRUE); 177} 178 179static void 180S_replace_separators(u_char * buf, int len, u_char sep, u_char new_sep) 181{ 182 int i; 183 184 for (i = 0; i < len; i++) { 185 if (buf[i] == sep) 186 buf[i] = new_sep; 187 } 188 return; 189} 190 191boolean_t 192macNCopt_encodeAFPPath(struct in_addr iaddr, uint16_t port, 193 const char * volname, uint32_t dirID, 194 uint8_t pathtype, const char * pathname, 195 char separator, void * buf, 196 int * len_p, dhcpo_err_str_t * err) 197{ 198 void * buf_p = buf; 199 int l; 200 201 l = (int)strlen(volname) + (int)strlen(pathname); 202 if (l > AFP_PATH_LIMIT) { 203 if (err) 204 snprintf(err->str, sizeof(err->str), 205 "volume/path name length %d > %d-byte limit", l, 206 AFP_PATH_LIMIT); 207 return (FALSE); 208 } 209 210 if ((l + AFP_PATH_OVERHEAD) > *len_p) { 211 if (err) 212 snprintf(err->str, sizeof(err->str), 213 "buffer too small: %d > %d", l + AFP_PATH_OVERHEAD, 214 *len_p); 215 return (FALSE); 216 } 217 *len_p = l + AFP_PATH_OVERHEAD; /* option len */ 218 219 *((struct in_addr *)buf_p) = iaddr; /* ip */ 220 buf_p += sizeof(iaddr); 221 222 *((u_short *)buf_p) = port; /* port */ 223 buf_p += sizeof(port); 224 225 l = (int)strlen(volname); /* VolName */ 226 *((u_char *)buf_p) = l; 227 buf_p++; 228 if (l) 229 bcopy(volname, (u_char *)buf_p, l); 230 buf_p += l; 231 232 *((uint32_t *)buf_p) = dirID; /* DirID */ 233 buf_p += sizeof(dirID); 234 235 *((uint8_t *)buf_p) = pathtype; /* AFPPathType */ 236 buf_p += sizeof(pathtype); 237 238 l = (int)strlen(pathname); /* PathName */ 239 *((uint8_t *)buf_p) = l; 240 buf_p++; 241 if (l) { 242 bcopy(pathname, (u_char *)buf_p, l); 243 S_replace_separators(buf_p, l, separator, AFP_PATH_SEPARATOR); 244 } 245 246 return (TRUE); 247} 248 249static void 250print_pstring(const uint8_t * option) 251 252{ 253 int i; 254 int len = option[0]; 255 256 for (i = 0; i < len; i++) { 257 char ch = option[1 + i]; 258 printf("%c", ch ? ch : '.'); 259 } 260} 261 262static void 263macNC_print_type(dhcptype_t type, void * opt, int option_len) 264{ 265 int offset; 266 uint8_t * option = opt; 267 268 switch (type) { 269 case macNCtype_afp_password_e: 270 if (option_len != AFP_PASSWORD_LEN) 271 printf("bad password field\n"); 272 else { 273 char buf[9]; 274 strncpy(buf, (char *)opt, AFP_PASSWORD_LEN); 275 buf[8] = '\0'; 276 printf("%s", buf); 277 } 278 break; 279 case macNCtype_afp_path_e: 280 offset = 0; 281 printf("("); 282 283 dhcptype_print(dhcptype_ip_e, option, option_len); 284 offset += 4; 285 286 printf(", "); 287 dhcptype_print(dhcptype_uint16_e, option + offset, option_len); 288 offset += 2; 289 290 printf(", "); 291 print_pstring(option + offset); 292 offset += option[offset] + 1; 293 294 printf(", "); 295 dhcptype_print(dhcptype_uint32_e, option + offset, option_len); 296 offset += 4; 297 298 printf(", "); 299 dhcptype_print(dhcptype_uint8_e, option + offset, option_len); 300 offset += 1; 301 302 printf(", "); 303 print_pstring(option + offset); 304 printf(")"); 305 break; 306 307 case macNCtype_pstring_e: { 308 print_pstring(option); 309 break; 310 } 311 default: 312 dhcptype_print(type, option, option_len); 313 break; 314 } 315 return; 316} 317 318boolean_t 319macNC_print_option(void * vopt) 320{ 321 u_char * opt = vopt; 322 u_char tag = opt[TAG_OFFSET]; 323 u_char option_len = opt[LEN_OFFSET]; 324 u_char * option = opt + OPTION_OFFSET; 325 const dhcptag_info_t * entry; 326 327 entry = macNCtag_info(tag); 328 if (entry == NULL) 329 return (FALSE); 330 { 331 const dhcptype_info_t * type = macNCtype_info(entry->type); 332 333 if (type == NULL) { 334 printf("unknown type %d\n", entry->type); 335 return (FALSE); 336 } 337 printf("%s (%s): ", entry->name, type->name); 338 if (tag == dhcptag_dhcp_message_type_e) 339 printf("%s ", dhcp_msgtype_names(*option)); 340 macNC_print_type(entry->type, option, option_len); 341 printf("\n"); 342 } 343 return (TRUE); 344} 345 346void 347macNCopt_print(dhcpol_t * list) 348{ 349 int i; 350 351 printf("Options count is %d\n", dhcpol_count(list)); 352 for (i = 0; i < dhcpol_count(list); i++) { 353 unsigned char * option = dhcpol_element(list, i); 354 if (macNC_print_option(option) == FALSE) 355 printf("undefined tag %d len %d\n", option[TAG_OFFSET], 356 option[LEN_OFFSET]); 357 } 358} 359 360#ifdef TEST_MACNC_OPTIONS 361 362/** 363 ** 364 ** Testing 1 2 3 365 ** 366 **/ 367u_char test[] = 368{ 369 dhcptag_subnet_mask_e, 370 4, 371 255, 255, 252, 0, 372 373 dhcptag_router_e, 374 12, 375 17, 202, 40, 1, 376 17, 202, 41, 1, 377 17, 202, 42, 1, 378 379 dhcptag_domain_name_server_e, 380 4, 381 17, 128, 100, 12, 382 383 dhcptag_host_name_e, 384 7, 385 's', 'i', 'e', 'g', 'd', 'i', '7', 386 387 dhcptag_pad_e, 388 389 dhcptag_all_subnets_local_e, 390 1, 391 0, 392 393 dhcptag_vendor_specific_e, 394 24, 395 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', 396 234, 212, 0, 1, 2, 3, 4, 5, 6, 7, 397 398 macNCtag_user_name_e, 399 10, 400 'M', 'a', 'c', 'N', 'C', ' ', '#', ' ', '1', '9', 401 402 macNCtag_shared_system_file_e, 403 29, 404 17, 202, 40, 191, 405 0x20, 0x00, 406 4, 'a', 'b', 'c', 'd', 407 0, 0, 0, 0, 408 2, 409 12, 0, 'e', 0, 'f', 0, 'g', 'h', 'i', 0, 'j', 'k', 'l', 410 411 dhcptag_end_e, 412}; 413 414#if 0 415u_char test[] = { 4160x01, 0x04, 0xff, 0x00, 0x00, 0x00, 0x03, 0x04, 0x0f, 0x03, 0x03, 0x09, 0x06, 4170x04, 0x0f, 0x03, 0x03, 0x09, 0xe8, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30, 4180xed, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30, 0xe9, 0x09, 0x08, 0x74, 0x65, 4190x73, 0x74, 0x69, 0x6e, 0x67, 0x32, 0xea, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06, 4200x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37, 4210xeb, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 4220x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37, 0xec, 0x18, 0x0f, 0x03, 0x03, 0x05, 4230x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 4240x33, 0x2e, 0x31, 0x37, 0xff, 425}; 426#endif 427 428int 429main() 430{ 431 dhcpo_err_str_t err; 432 dhcpol_t list; 433 434 dhcpol_init(&list); 435 if (dhcpol_parse_buffer(&list, test, sizeof(test), &err) == FALSE) { 436 printf("parse test failed, %s\n", err.str); 437 exit(1); 438 } 439 macNCopt_print(&list); 440 exit(0); 441#if 0 442 { 443 struct in_addr iaddr; 444 int i = sizeof(iaddr); 445 446 if ([options str:"17.202.42.129" ToType:dhcptype_ip_e 447 Buffer:(void *)&iaddr Length:&i] == FALSE) { 448 printf("conversion failed %s\n", [options errString]); 449 } 450 else { 451 printf("ip address should be 17.202.42.129: "); 452 [options printType:dhcptype_ip_e Size:i Option:(void *)&iaddr 453 Length:i]; 454 printf("\n"); 455 } 456 } 457 { 458 unsigned char buf[32] = "Mac NC #33"; 459 unsigned char buf2[34]; 460 int len = sizeof(buf2); 461 462 if ([options str:buf ToType:macNCtype_pstring_e Buffer:buf2 463 Length:&len] == FALSE) { 464 printf("conversion failed %s\n", [options errString]); 465 } 466 else { 467 printf("macNCtype string should be %s:", buf); 468 [options printType:macNCtype_pstring_e Size:0 Option:buf2 469 Length:len]; 470 printf("\n"); 471 } 472 } 473 { 474 struct in_addr iaddr[10]; 475 int l = sizeof(iaddr); 476 u_char * strList[] = { "17.202.40.1", "17.202.41.1", "17.202.42.1", 477 "17.202.43.1" }; 478 int num = sizeof(strList) / sizeof(*strList); 479 480 if ([options strList:strList Number:num Tag:dhcptag_router_e 481 Buffer:(void *)iaddr Length:&l] == FALSE) { 482 printf("conversion failed %s\n", [options errString]); 483 } 484 else { 485 [options printType:dhcptype_ip_mult_e Size:4 Option:(void *)iaddr 486 Length:l]; 487 printf("\n"); 488 } 489 } 490 { 491 u_char buf[100]; 492 u_char * strList[] = { "17.86.91.2", "0x100", "0", "greatVolumeName", 493 "/spectacular/path/name/eh" }; 494 int l = sizeof(buf); 495 int num = sizeof(strList) / sizeof(*strList); 496 497 if ([macNCOptions strList:strList Number:num 498 Tag:macNCtag_system_path_shared_e Buffer:(void *)buf Length:&l 499 ErrorString:[options errString]] == FALSE) { 500 printf("conversion failed %s\n", [options errString]); 501 } 502 else { 503 printf("conversion OK\n"); 504 [options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf 505 Length:l]; 506 printf("\n"); 507 } 508 } 509 { 510 u_char buf[100]; 511 int l = sizeof(buf); 512 struct in_addr iaddr; 513 514 iaddr.s_addr = inet_addr("17.202.101.100"); 515 if ([macNCOptions encodeAFPPath 516 : iaddr 517 : 0x1234 518 : "volumeName" 519 : AFP_DIRID_NULL 520 : AFP_PATHTYPE_LONG 521 : "this:is:the:path" 522 : ':' 523 Into: (void *)buf 524 Length: &l 525 ErrorString: [options errString]] == FALSE) { 526 printf("conversion path failed %s\n", [options errString]); 527 } 528 else { 529 printf("conversion OK\n"); 530 [options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf 531 Length:l]; 532 printf("\n"); 533 } 534 535 } 536 [options free]; 537 options = nil; 538 { 539 unsigned char buf[300]; 540 int len = sizeof(buf); 541 id o = [[macNCOptions alloc] initWithBuffer:(void *)buf Size:len]; 542 543 if (o == nil) { 544 printf("initWithBuffer failed\n"); 545 } 546 else { 547 if ([o addOption:macNCtag_user_name_e FromString:"Mac NC # 22"] 548 == FALSE 549 || 550 [o addOption:dhcptag_subnet_mask_e FromString:"255.255.255.0"] 551 == FALSE 552 || 553 [o addOption:dhcptag_end_e Length:0 Data:0] == FALSE 554 ) { 555 printf("%s", [o errString]); 556 } 557 else { 558 [o parse]; 559 [o print]; 560 } 561 } 562 } 563 564#endif 565 566 exit(0); 567} 568#endif /* TEST_MACNC_OPTIONS */ 569 570