#import <unistd.h>
#import <stdlib.h>
#import <stdio.h>
#import <sys/types.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <string.h>
#import "rfc_options.h"
#import "macnc_options.h"
typedef struct {
macNCtype_t type;
dhcptype_info_t info;
} macNCtype_info_t;
static const macNCtype_info_t macNCtype_info_table[] = {
{ macNCtype_pstring_e, { 1, dhcptype_none_e, "PString" } },
{ macNCtype_afp_path_e, { 0, dhcptype_none_e, "AFP path" } },
{ macNCtype_afp_password_e, { 8, dhcptype_none_e, "AFP password" } },
};
static const int macNCtype_info_size = sizeof(macNCtype_info_table)
/ sizeof(macNCtype_info_t);
typedef struct {
macNCtag_t tag;
dhcptag_info_t info;
} macNCtag_info_t;
static const macNCtag_info_t macNCtag_info_table[] = {
{ macNCtag_client_version_e, {dhcptype_uint32_e, "macNC_client_version" } },
{ macNCtag_client_info_e, { dhcptype_opaque_e, "macNC_client_info" } },
{ macNCtag_server_version_e, { dhcptype_uint32_e, "macNC_server_version" } },
{ macNCtag_server_info_e, { dhcptype_opaque_e, "macNC_server_info" } },
{ macNCtag_user_name_e, { dhcptype_string_e, "macNC_user_name" } },
{ macNCtag_password_e, { macNCtype_afp_password_e, "macNC_password" } },
{ macNCtag_shared_system_file_e,
{ macNCtype_afp_path_e, "macNC_shared_system_file" } },
{ macNCtag_private_system_file_e,
{ macNCtype_afp_path_e, "macNC_private_system_file" } },
{ macNCtag_page_file_e,
{ macNCtype_afp_path_e, "macNC_page_file" } },
{ macNCtag_MacOS_machine_name_e,
{ dhcptype_string_e, "macNC_MacOS_machine_name" } },
{ macNCtag_shared_system_shadow_file_e,
{ macNCtype_afp_path_e, "macNC_shared_system_shadow_file" } },
{ macNCtag_private_system_shadow_file_e,
{ macNCtype_afp_path_e, "macNC_private_system_shadow_file" } },
};
static int macNCtag_info_size = sizeof(macNCtag_info_table)
/ sizeof(macNCtag_info_t);
static const dhcptype_info_t *
macNCtype_info(int type)
{
int i;
const dhcptype_info_t * t;
for (i = 0; i < macNCtype_info_size; i++) {
if (type == macNCtype_info_table[i].type)
return (&macNCtype_info_table[i].info);
}
t = dhcptype_info(type);
if (t)
return (t);
return (NULL);
}
static const dhcptag_info_t *
macNCtag_info(int tag)
{
int i;
const dhcptag_info_t * t;
for (i = 0; i < macNCtag_info_size; i++) {
if (tag == macNCtag_info_table[i].tag)
return (&macNCtag_info_table[i].info);
}
t = dhcptag_info(tag);
if (t)
return (t);
return (NULL);
}
boolean_t
macNCopt_str_to_type(unsigned char * str,
int type, void * buf, int * len_p,
unsigned char * err)
{
const dhcptype_info_t * type_info = macNCtype_info(type);
if (err)
err[0] = '\0';
switch (type) {
case macNCtype_afp_password_e: {
int len = strlen(str);
if (*len_p < AFP_PASSWORD_LEN) {
if (err)
sprintf(err, "%s: buffer too small (%d < %d)",
type_info->name, *len_p, AFP_PASSWORD_LEN);
return (FALSE);
}
if (len > AFP_PASSWORD_LEN) {
if (err)
sprintf(err, "%s: string too large (%d > %d)",
type_info->name, len, AFP_PASSWORD_LEN);
return (FALSE);
}
*len_p = AFP_PASSWORD_LEN;
bzero(buf, AFP_PASSWORD_LEN);
strncpy((u_char *)buf, str, len);
}
break;
case macNCtype_pstring_e: {
int len = strlen(str);
if (*len_p < (len + 1)) {
if (err)
sprintf(err, "%s: buffer too small (%d < %d)",
type_info->name, *len_p, len + 1);
return (FALSE);
}
((u_char *)buf)[0] = len;
bcopy(str, buf + 1, len);
*len_p = len + 1;
}
break;
case macNCtype_afp_path_e:
if (err)
sprintf(err, "%s: not supported", type_info->name);
return (FALSE);
break;
default:
return (dhcptype_from_str(str, type, buf, len_p, err));
break;
}
return (TRUE);
}
static void
S_replace_separators(u_char * buf, int len, u_char sep, u_char new_sep)
{
int i;
for (i = 0; i < len; i++) {
if (buf[i] == sep)
buf[i] = new_sep;
}
return;
}
boolean_t
macNCopt_encodeAFPPath(struct in_addr iaddr, u_short port,
u_char * volname, unsigned long dirID,
u_char pathtype, u_char * pathname,
u_char separator, void * buf,
int * len_p, u_char * err)
{
void * buf_p = buf;
int l;
l = strlen(volname) + strlen(pathname);
if (l > AFP_PATH_LIMIT) {
if (err)
sprintf(err, "volume/path name length %d > %d-byte limit", l,
AFP_PATH_LIMIT);
return (FALSE);
}
if ((l + AFP_PATH_OVERHEAD) > *len_p) {
if (err)
sprintf(err, "buffer too small: %d > %d", l + AFP_PATH_OVERHEAD,
*len_p);
return (FALSE);
}
*len_p = l + AFP_PATH_OVERHEAD;
*((struct in_addr *)buf_p) = iaddr;
buf_p += sizeof(iaddr);
*((u_short *)buf_p) = port;
buf_p += sizeof(port);
l = strlen(volname);
*((u_char *)buf_p) = l;
buf_p++;
if (l)
bcopy(volname, (u_char *)buf_p, l);
buf_p += l;
*((u_long *)buf_p) = dirID;
buf_p += sizeof(dirID);
*((u_char *)buf_p) = pathtype;
buf_p += sizeof(pathtype);
l = strlen(pathname);
*((u_char *)buf_p) = l;
buf_p++;
if (l) {
bcopy(pathname, (u_char *)buf_p, l);
S_replace_separators(buf_p, l, separator, AFP_PATH_SEPARATOR);
}
return (TRUE);
}
static void
print_pstring(unsigned char * option)
{
int i;
for (i = 0; i < option[0]; i++) {
u_char ch = option[1 + i];
printf("%c", ch ? ch : '.');
}
}
static void
macNC_print_type(dhcptype_t type, void * opt, int option_len)
{
int offset;
unsigned char * option = opt;
switch (type) {
case macNCtype_afp_password_e:
if (option_len != AFP_PASSWORD_LEN)
printf("bad password field\n");
else {
u_char buf[9];
strncpy(buf, (u_char *)opt, AFP_PASSWORD_LEN);
buf[8] = '\0';
printf(buf);
}
break;
case macNCtype_afp_path_e:
offset = 0;
printf("(");
dhcptype_print(dhcptype_ip_e, option, option_len);
offset += 4;
printf(", ");
dhcptype_print(dhcptype_uint16_e, option + offset, option_len);
offset += 2;
printf(", ");
print_pstring(option + offset);
offset += option[offset] + 1;
printf(", ");
dhcptype_print(dhcptype_uint32_e, option + offset, option_len);
offset += 4;
printf(", ");
dhcptype_print(dhcptype_uint8_e, option + offset, option_len);
offset += 1;
printf(", ");
print_pstring(option + offset);
printf(")");
break;
case macNCtype_pstring_e: {
print_pstring(option);
break;
}
default:
dhcptype_print(type, option, option_len);
break;
}
return;
}
boolean_t
macNC_print_option(void * vopt)
{
u_char * opt = vopt;
u_char tag = opt[TAG_OFFSET];
u_char option_len = opt[LEN_OFFSET];
u_char * option = opt + OPTION_OFFSET;
const dhcptag_info_t * entry;
entry = macNCtag_info(tag);
if (entry == NULL)
return (FALSE);
{
const dhcptype_info_t * type = macNCtype_info(entry->type);
if (type == NULL) {
printf("unknown type %d\n", entry->type);
return (FALSE);
}
printf("%s (%s): ", entry->name, type->name);
if (tag == dhcptag_dhcp_message_type_e)
printf("%s ", dhcp_msgtype_names(*option));
macNC_print_type(entry->type, option, option_len);
printf("\n");
}
return (TRUE);
}
void
macNCopt_print(dhcpol_t * list)
{
int i;
printf("Options count is %d\n", dhcpol_count(list));
for (i = 0; i < dhcpol_count(list); i++) {
unsigned char * option = dhcpol_element(list, i);
if (macNC_print_option(option) == FALSE)
printf("undefined tag %d len %d\n", option[TAG_OFFSET],
option[LEN_OFFSET]);
}
}
#ifdef TESTING
u_char test[] =
{
dhcptag_subnet_mask_e,
4,
255, 255, 252, 0,
dhcptag_router_e,
12,
17, 202, 40, 1,
17, 202, 41, 1,
17, 202, 42, 1,
dhcptag_domain_name_server_e,
4,
17, 128, 100, 12,
dhcptag_host_name_e,
7,
's', 'i', 'e', 'g', 'd', 'i', '7',
dhcptag_pad_e,
dhcptag_all_subnets_local_e,
1,
0,
dhcptag_vendor_specific_e,
24,
't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't',
234, 212, 0, 1, 2, 3, 4, 5, 6, 7,
macNCtag_user_name_e,
10,
'M', 'a', 'c', 'N', 'C', ' ', '#', ' ', '1', '9',
macNCtag_shared_system_file_e,
29,
17, 202, 40, 191,
0x20, 0x00,
4, 'a', 'b', 'c', 'd',
0, 0, 0, 0,
2,
12, 0, 'e', 0, 'f', 0, 'g', 'h', 'i', 0, 'j', 'k', 'l',
dhcptag_end_e,
};
#if 0
u_char test[] = {
0x01, 0x04, 0xff, 0x00, 0x00, 0x00, 0x03, 0x04, 0x0f, 0x03, 0x03, 0x09, 0x06,
0x04, 0x0f, 0x03, 0x03, 0x09, 0xe8, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30,
0xed, 0x09, 0x08, 0x6d, 0x61, 0x63, 0x6e, 0x63, 0x30, 0x30, 0x30, 0xe9, 0x09, 0x08, 0x74, 0x65,
0x73, 0x74, 0x69, 0x6e, 0x67, 0x32, 0xea, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06,
0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37,
0xeb, 0x18, 0x0f, 0x03, 0x03, 0x05, 0x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73,
0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e, 0x33, 0x2e, 0x31, 0x37, 0xec, 0x18, 0x0f, 0x03, 0x03, 0x05,
0x02, 0x24, 0x00, 0x06, 0x64, 0x75, 0x63, 0x61, 0x74, 0x73, 0x09, 0x31, 0x35, 0x2e, 0x33, 0x2e,
0x33, 0x2e, 0x31, 0x37, 0xff,
};
#endif
main()
{
u_char err[256];
dhcpol_t list;
dhcpol_init(&list);
if (dhcpopt_parse_buffer(&list, test, sizeof(test), err)
!= dhcpopt_ret_success_e) {
printf("parse test failed, %s\n", err);
exit(1);
}
macNCopt_print(&list);
exit(0);
#if 0
{
struct in_addr iaddr;
int i = sizeof(iaddr);
if ([options str:"17.202.42.129" ToType:dhcptype_ip_e
Buffer:(void *)&iaddr Length:&i] == FALSE) {
printf("conversion failed %s\n", [options errString]);
}
else {
printf("ip address should be 17.202.42.129: ");
[options printType:dhcptype_ip_e Size:i Option:(void *)&iaddr
Length:i];
printf("\n");
}
}
{
unsigned char buf[32] = "Mac NC #33";
unsigned char buf2[34];
int len = sizeof(buf2);
if ([options str:buf ToType:macNCtype_pstring_e Buffer:buf2
Length:&len] == FALSE) {
printf("conversion failed %s\n", [options errString]);
}
else {
printf("macNCtype string should be %s:", buf);
[options printType:macNCtype_pstring_e Size:0 Option:buf2
Length:len];
printf("\n");
}
}
{
struct in_addr iaddr[10];
int l = sizeof(iaddr);
u_char * strList[] = { "17.202.40.1", "17.202.41.1", "17.202.42.1",
"17.202.43.1" };
int num = sizeof(strList) / sizeof(*strList);
if ([options strList:strList Number:num Tag:dhcptag_router_e
Buffer:(void *)iaddr Length:&l] == FALSE) {
printf("conversion failed %s\n", [options errString]);
}
else {
[options printType:dhcptype_ip_mult_e Size:4 Option:(void *)iaddr
Length:l];
printf("\n");
}
}
{
u_char buf[100];
u_char * strList[] = { "17.86.91.2", "0x100", "0", "greatVolumeName",
"/spectacular/path/name/eh" };
int l = sizeof(buf);
int num = sizeof(strList) / sizeof(*strList);
if ([macNCOptions strList:strList Number:num
Tag:macNCtag_system_path_shared_e Buffer:(void *)buf Length:&l
ErrorString:[options errString]] == FALSE) {
printf("conversion failed %s\n", [options errString]);
}
else {
printf("conversion OK\n");
[options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf
Length:l];
printf("\n");
}
}
{
u_char buf[100];
int l = sizeof(buf);
struct in_addr iaddr;
iaddr.s_addr = inet_addr("17.202.101.100");
if ([macNCOptions encodeAFPPath
: iaddr
: 0x1234
: "volumeName"
: AFP_DIRID_NULL
: AFP_PATHTYPE_LONG
: "this:is:the:path"
: ':'
Into: (void *)buf
Length: &l
ErrorString: [options errString]] == FALSE) {
printf("conversion path failed %s\n", [options errString]);
}
else {
printf("conversion OK\n");
[options printType:macNCtype_afp_path_e Size:0 Option:(void *)buf
Length:l];
printf("\n");
}
}
[options free];
options = nil;
{
unsigned char buf[300];
int len = sizeof(buf);
id o = [[macNCOptions alloc] initWithBuffer:(void *)buf Size:len];
if (o == nil) {
printf("initWithBuffer failed\n");
}
else {
if ([o addOption:macNCtag_user_name_e FromString:"Mac NC # 22"]
== FALSE
||
[o addOption:dhcptag_subnet_mask_e FromString:"255.255.255.0"]
== FALSE
||
[o addOption:dhcptag_end_e Length:0 Data:0] == FALSE
) {
printf("%s", [o errString]);
}
else {
[o parse];
[o print];
}
}
}
#endif
exit(0);
}
#endif TESTING