static int dsi_parse_versions(struct afp_server * server, char * msg) { unsigned char num_versions = msg[0]; int i,j=0; char * p; unsigned char len; char tmpversionname[33]; struct afp_versions * tmpversion; memset(server->versions,0, SERVER_MAX_VERSIONS); if (num_versions > SERVER_MAX_VERSIONS) num_versions = SERVER_MAX_VERSIONS; p=msg+1; for (i=0;i<num_versions;i++) { len=copy_from_pascal(tmpversionname,p,33)+1; for (tmpversion=afp_versions;tmpversion->av_name;tmpversion++) { if (strcmp(tmpversion->av_name,tmpversionname)==0) { server->versions[j]=tmpversion->av_number; j++; break; } } p+=len; } return 0; }
static int dsi_parse_uams(struct afp_server * server, char * msg) { unsigned char num_uams = msg[0]; unsigned char len; int i; char * p; char ua_name[AFP_UAM_LENGTH+1]; server->supported_uams= 0; memset(ua_name,0,AFP_UAM_LENGTH+1); if (num_uams > SERVER_MAX_UAMS) num_uams = SERVER_MAX_UAMS; p=msg+1; for (i=0;i<num_uams;i++) { len=copy_from_pascal(ua_name,p,AFP_UAM_LENGTH)+1; server->supported_uams|=uam_string_to_bitmap(ua_name); p+=len; } return 0; }
/* FIXME: should do bounds checking */ int parse_reply_block(struct afp_server *server, char * buf, unsigned int size, unsigned char isdir, unsigned int filebitmap, unsigned int dirbitmap, struct afp_file_info * filecur) { unsigned short bitmap; char * p2; memset(filecur,0,sizeof(struct afp_file_info)); filecur->isdir=isdir; p2=buf; if (isdir) bitmap=dirbitmap ; else bitmap=filebitmap; if (bitmap & kFPAttributeBit) { unsigned short * attr = (void *) p2; filecur->attributes=ntohs(*attr); p2+=2; } if (bitmap & kFPParentDirIDBit) { unsigned int * did= (void *) p2; filecur->did=ntohl(*did); p2+=4; } if (bitmap & kFPCreateDateBit) { unsigned int * date= (void *) p2; filecur->creation_date=AD_DATE_TO_UNIX(*date); p2+=4; } if (bitmap & kFPModDateBit) { unsigned int * date= (void *) p2; filecur->modification_date=AD_DATE_TO_UNIX(*date); p2+=4; } if (bitmap & kFPBackupDateBit) { unsigned int * date= (void *) p2; filecur->backup_date=AD_DATE_TO_UNIX(*date); p2+=4; } if (bitmap & kFPFinderInfoBit) { memcpy(filecur->finderinfo,p2,32); p2+=32; } if (bitmap & kFPLongNameBit) { unsigned short *offset = (void *) p2; copy_from_pascal(filecur->name,buf+(ntohs(*offset)),AFP_MAX_PATH); p2+=2; } if (bitmap & kFPShortNameBit) { p2+=2; } if (bitmap & kFPNodeIDBit) { unsigned int * id = (void *) p2; filecur->fileid=ntohl(*id); p2+=4; } if (isdir) { if (bitmap & kFPOffspringCountBit) { unsigned short *offspring = (void *) p2; filecur->offspring=ntohs(*offspring); p2+=2; } if (bitmap & kFPOwnerIDBit) { unsigned int * owner= (void *) p2; filecur->unixprivs.uid=ntohl(*owner); p2+=4; } if (bitmap & kFPGroupIDBit) { unsigned int * group= (void *) p2; filecur->unixprivs.gid=ntohl(*group); p2+=4; } if (bitmap & kFPAccessRightsBit) { unsigned int * access= (void *) p2; filecur->accessrights=ntohl(*access); p2+=4; } } else { if (bitmap & kFPDataForkLenBit) { unsigned int * len = (void *) p2; filecur->size=ntohl(*len); p2+=4; } if (bitmap & kFPRsrcForkLenBit) { unsigned int * size = (void *) p2; filecur->resourcesize=ntohl(*size); p2+=4; } if (bitmap & kFPExtDataForkLenBit) { unsigned long long * len = (void *) p2; filecur->size=ntoh64(*len); p2+=8; } if (bitmap & kFPLaunchLimitBit) { p2+=2; } } if (bitmap & kFPUTF8NameBit) { unsigned short *offset = (void *) p2; copy_from_pascal_two(filecur->name,buf+(ntohs(*offset))+4, AFP_MAX_PATH); p2+=2; p2+=4; } if (bitmap & kFPExtRsrcForkLenBit) { unsigned long long * size = (void *) p2; filecur->resourcesize=ntoh64(*size); p2+=8; } if (bitmap & kFPUnixPrivsBit) { struct afp_unixprivs *unixpriv = (void *) p2; filecur->unixprivs.uid=ntohl(unixpriv->uid); filecur->unixprivs.gid=ntohl(unixpriv->gid); filecur->unixprivs.permissions=ntohl(unixpriv->permissions); filecur->unixprivs.ua_permissions=ntohl(unixpriv->ua_permissions); p2+=sizeof(*unixpriv); } return 0; }
void dsi_getstatus_reply(struct afp_server * server) { /* Todo: check for buffer overruns */ char * data, *p, *p2; int len; uint16_t * offset; /* This is the fixed portion */ struct dsi_getstatus_header { struct dsi_header dsi __attribute__((__packed__)); uint16_t machine_offset; uint16_t version_offset; uint16_t uams_offset; uint16_t icon_offset; uint16_t flags ; } __attribute__((__packed__)) * reply1 = (void *) server->incoming_buffer; struct reply2 { uint16_t signature_offset; uint16_t networkaddress_offset; uint16_t directoryservices_offset; uint16_t utf8servername_offset; } __attribute__((__packed__)) * reply2; if (server->data_read < (sizeof(*reply1) + sizeof(*reply2))) { log_for_client(NULL,AFPFSD,LOG_ERR, "Got incomplete data for getstatus\n"); return ; } data = (char * ) server->incoming_buffer + sizeof(struct dsi_header); /* First, get the fixed portion */ p=data + ntohs(reply1->machine_offset); copy_from_pascal(server->machine_type,p,AFP_MACHINETYPE_LEN); p=data + ntohs(reply1->version_offset); dsi_parse_versions(server, p); p=data + ntohs(reply1->uams_offset); dsi_parse_uams(server, p); if (ntohs(reply1->icon_offset)>0) { /* The icon and mask are optional */ p=data + ntohs(reply1->icon_offset); memcpy(server->icon,p,256); } server->flags=ntohs(reply1->flags); p=(void *)((unsigned int) server->incoming_buffer + sizeof(*reply1)); p+=copy_from_pascal(server->server_name,p,AFP_SERVER_NAME_LEN)+1; /* Now work our way through the variable bits */ /* First, make sure we're on an even boundary */ if (((uint64_t) p) & 0x1) p++; /* Get the signature */ offset = (uint16_t *) p; memcpy(server->signature, ((void *) data)+ntohs(*offset), AFP_SIGNATURE_LEN); p+=2; /* The network addresses */ if (server->flags & kSupportsTCP) { offset = (uint16_t *) p; /* We don't actually do anything with the network addresses, * but if we did, it'd go here */ p+=2; } /* The directory names */ if (server->flags & kSupportsDirServices) { offset = (uint16_t *) p; /* We don't actually do anything with the directory names, * but if we did, it'd go here */ p+=2; } if (server->flags & kSupportsUTF8SrvrName) { /* And now the UTF8 server name */ offset = (uint16_t *) p; p2=((void *) data)+ntohs(*offset); /* Skip the hint character */ p2+=1; len=copy_from_pascal(server->server_name_utf8,p2, AFP_SERVER_NAME_UTF8_LEN); /* This is a workaround. There's a bug in netatalk that in some * circumstances puts the UTF8 servername off by one character */ if (len==0) { p2++; len=copy_from_pascal(server->server_name_utf8,p2, AFP_SERVER_NAME_UTF8_LEN); } convert_utf8dec_to_utf8pre(server->server_name_utf8, strlen(server->server_name_utf8), server->server_name_printable, AFP_SERVER_NAME_UTF8_LEN); } else { /* We don't have a UTF8 servername, so let's make one */ iconv_t cd; size_t inbytesleft = strlen(server->server_name); size_t outbytesleft = AFP_SERVER_NAME_UTF8_LEN; char * inbuf = server->server_name; char * outbuf = server->server_name_printable; if ((cd = iconv_open("MACINTOSH","UTF-8")) == (iconv_t) -1) return; iconv(cd,&inbuf,&inbytesleft, &outbuf, &outbytesleft); iconv_close(cd); } }