1/* 2 * Copyright (c) 1990,1993 Regents of The University of Michigan. 3 * All Rights Reserved. See COPYRIGHT. 4 */ 5 6#ifdef HAVE_CONFIG_H 7#include "config.h" 8#endif /* HAVE_CONFIG_H */ 9 10#include <stdio.h> 11#include <stdlib.h> 12#include <unistd.h> 13#include <ctype.h> 14#include <string.h> 15#include <time.h> 16#include <sys/types.h> 17#include <sys/stat.h> 18#include <fcntl.h> 19#include <sys/socket.h> 20#include <atalk/logger.h> 21 22#if 0 23#ifdef BSD4_4 24#include <sys/param.h> 25#ifndef HAVE_GETHOSTID 26#include <sys/sysctl.h> 27#endif /* HAVE_GETHOSTID */ 28#endif /* BSD4_4 */ 29#endif 30 31#include <netatalk/at.h> 32#include <netatalk/endian.h> 33#include <atalk/dsi.h> 34#include <atalk/atp.h> 35#include <atalk/asp.h> 36#include <atalk/nbp.h> 37#include <atalk/unicode.h> 38#include <atalk/util.h> 39#include <atalk/globals.h> 40 41#include "status.h" 42#include "afp_config.h" 43#include "icon.h" 44 45static size_t maxstatuslen = 0; 46 47static void status_flags(char *data, const int notif, const int ipok, 48 const unsigned char passwdbits, const int dirsrvcs _U_, int flags) 49{ 50 uint16_t status; 51 52 status = AFPSRVRINFO_COPY 53 | AFPSRVRINFO_SRVSIGNATURE 54 | AFPSRVRINFO_SRVMSGS 55 | AFPSRVRINFO_FASTBOZO 56 | AFPSRVRINFO_SRVRDIR 57 | AFPSRVRINFO_SRVUTF8 58 | AFPSRVRINFO_EXTSLEEP; 59 60 if (passwdbits & PASSWD_SET) /* some uams may not allow this. */ 61 status |= AFPSRVRINFO_PASSWD; 62 if (passwdbits & PASSWD_NOSAVE) 63 status |= AFPSRVRINFO_NOSAVEPASSWD; 64 if (ipok) /* only advertise tcp/ip if we have a valid address */ 65 status |= AFPSRVRINFO_TCPIP; 66 if (notif) /* Default is yes */ 67 status |= AFPSRVRINFO_SRVNOTIFY; 68 if (flags & OPTION_UUID) 69 status |= AFPSRVRINFO_UUID; 70 71 status = htons(status); 72 memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status)); 73} 74 75static int status_server(char *data, const char *server, const struct afp_options *options) 76{ 77 char *start = data; 78 char *Obj, *Type, *Zone; 79 char buf[32]; 80 u_int16_t status; 81 size_t len; 82 83 /* make room for all offsets before server name */ 84 data += AFPSTATUS_PRELEN; 85 86 /* extract the obj part of the server */ 87 Obj = (char *) server; 88 nbp_name(server, &Obj, &Type, &Zone); 89 if ((size_t)-1 == (len = convert_string( 90 options->unixcharset, options->maccharset, 91 Obj, -1, buf, sizeof(buf))) ) { 92 len = MIN(strlen(Obj), 31); 93 *data++ = len; 94 memcpy( data, Obj, len ); 95 LOG ( log_error, logtype_afpd, "Could not set servername, using fallback"); 96 } else { 97 *data++ = len; 98 memcpy( data, buf, len ); 99 } 100 if ((len + 1) & 1) /* pad server name and length byte to even boundary */ 101 len++; 102 data += len; 103 104 /* make room for signature and net address offset. save location of 105 * signature offset. we're also making room for directory names offset 106 * and the utf-8 server name offset. 107 * 108 * NOTE: technically, we don't need to reserve space for the 109 * signature and net address offsets if they're not going to be 110 * used. as there are no offsets after them, it doesn't hurt to 111 * have them specified though. so, we just do that to simplify 112 * things. 113 * 114 * NOTE2: AFP3.1 Documentation states that the directory names offset 115 * is a required feature, even though it can be set to zero. 116 */ 117 len = data - start; 118 status = htons(len + AFPSTATUS_POSTLEN); 119 memcpy(start + AFPSTATUS_MACHOFF, &status, sizeof(status)); 120 return len; /* return the offset to beginning of signature offset */ 121} 122 123static void status_machine(char *data) 124{ 125 char *start = data; 126 u_int16_t status; 127 int len; 128#ifdef AFS 129 const char *machine = "afs"; 130#else /* !AFS */ 131 const char *machine = "Netatalk %s"; 132#endif /* AFS */ 133 char buf[64]; 134 135 memcpy(&status, start + AFPSTATUS_MACHOFF, sizeof(status)); 136 data += ntohs( status ); 137 138 // len = strlen( machine ); 139 len = snprintf(buf, 64, machine, VERSION); 140 *data++ = len; 141 memcpy( data, buf, len ); 142 data += len; 143 144 status = htons(data - start); 145 memcpy(start + AFPSTATUS_VERSOFF, &status, sizeof(status)); 146} 147 148/* server signature is a 16-byte quantity */ 149static u_int16_t status_signature(char *data, int *servoffset, 150 const struct afp_options *options) 151{ 152 char *status; 153 u_int16_t offset, sigoff; 154 155 status = data; 156 157 /* get server signature offset */ 158 memcpy(&offset, data + *servoffset, sizeof(offset)); 159 sigoff = offset = ntohs(offset); 160 161 /* jump to server signature offset */ 162 data += offset; 163 164 memset(data, 0, 16); 165 memcpy(data, options->signature, 16); 166 data += 16; 167 168 /* calculate net address offset */ 169 *servoffset += sizeof(offset); 170 offset = htons(data - status); 171 memcpy(status + *servoffset, &offset, sizeof(offset)); 172 return sigoff; 173} 174 175static size_t status_netaddress(char *data, int *servoffset, 176 const ASP asp, const DSI *dsi, 177 const struct afp_options *options) 178{ 179 char *begin; 180 u_int16_t offset; 181 size_t addresses_len = 0; 182 183 begin = data; 184 185 /* get net address offset */ 186 memcpy(&offset, data + *servoffset, sizeof(offset)); 187 data += ntohs(offset); 188 189 /* format: 190 Address count (byte) 191 len (byte = sizeof(length + address type + address) 192 address type (byte, ip address = 0x01, ip + port = 0x02, 193 ddp address = 0x03, fqdn = 0x04) 194 address (up to 254 bytes, ip = 4, ip + port = 6, ddp = 4) 195 */ 196 197 /* number of addresses. this currently screws up if we have a dsi 198 connection, but we don't have the ip address. to get around this, 199 we turn off the status flag for tcp/ip. */ 200 *data++ = ((options->fqdn && dsi)? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0) + 201 (((options->flags & OPTION_ANNOUNCESSH) && options->fqdn && dsi)? 1 : 0); 202 203 /* ip address */ 204 if (dsi) { 205 if (dsi->server.ss_family == AF_INET) { /* IPv4 */ 206 const struct sockaddr_in *inaddr = (struct sockaddr_in *)&dsi->server; 207 if (inaddr->sin_port == htons(DSI_AFPOVERTCP_PORT)) { 208 *data++ = 6; /* length */ 209 *data++ = 0x01; /* basic ip address */ 210 memcpy(data, &inaddr->sin_addr.s_addr, 211 sizeof(inaddr->sin_addr.s_addr)); 212 data += sizeof(inaddr->sin_addr.s_addr); 213 addresses_len += 7; 214 } else { 215 /* ip address + port */ 216 *data++ = 8; 217 *data++ = 0x02; /* ip address with port */ 218 memcpy(data, &inaddr->sin_addr.s_addr, 219 sizeof(inaddr->sin_addr.s_addr)); 220 data += sizeof(inaddr->sin_addr.s_addr); 221 memcpy(data, &inaddr->sin_port, sizeof(inaddr->sin_port)); 222 data += sizeof(inaddr->sin_port); 223 addresses_len += 9; 224 } 225 } else { /* IPv6 */ 226 const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&dsi->server; 227 if (sa6->sin6_port == htons(DSI_AFPOVERTCP_PORT)) { 228 *data++ = 18; /* length */ 229 *data++ = 6; /* type */ 230 memcpy(data, &sa6->sin6_addr.s6_addr, sizeof(sa6->sin6_addr.s6_addr)); 231 data += sizeof(sa6->sin6_addr.s6_addr); 232 addresses_len += 19; 233 } else { 234 /* ip address + port */ 235 *data++ = 20; /* length */ 236 *data++ = 7; /* type*/ 237 memcpy(data, &sa6->sin6_addr.s6_addr, sizeof(sa6->sin6_addr.s6_addr)); 238 data += sizeof(sa6->sin6_addr.s6_addr); 239 memcpy(data, &sa6->sin6_port, sizeof(sa6->sin6_port)); 240 data += sizeof(sa6->sin6_port); 241 addresses_len += 21; 242 } 243 244 } 245 } 246 247 /* handle DNS names */ 248 if (options->fqdn && dsi) { 249 size_t len = strlen(options->fqdn); 250 if ( len + 2 + addresses_len < maxstatuslen - offset) { 251 *data++ = len +2; 252 *data++ = 0x04; 253 memcpy(data, options->fqdn, len); 254 data += len; 255 addresses_len += len+2; 256 } 257 258 /* Annouce support for SSH tunneled AFP session, 259 * this feature is available since 10.3.2. 260 * According to the specs (AFP 3.1 p.225) this should 261 * be an IP+Port style value, but it only works with 262 * a FQDN. OSX Server uses FQDN as well. 263 */ 264 if ( len + 2 + addresses_len < maxstatuslen - offset) { 265 if (options->flags & OPTION_ANNOUNCESSH) { 266 *data++ = len +2; 267 *data++ = 0x05; 268 memcpy(data, options->fqdn, len); 269 data += len; 270 } 271 } 272 } 273 274#ifndef NO_DDP 275 if (asp) { 276 const struct sockaddr_at *ddpaddr = atp_sockaddr(asp->asp_atp); 277 278 /* ddp address */ 279 *data++ = 6; 280 *data++ = 0x03; /* ddp address */ 281 memcpy(data, &ddpaddr->sat_addr.s_net, sizeof(ddpaddr->sat_addr.s_net)); 282 data += sizeof(ddpaddr->sat_addr.s_net); 283 memcpy(data, &ddpaddr->sat_addr.s_node, 284 sizeof(ddpaddr->sat_addr.s_node)); 285 data += sizeof(ddpaddr->sat_addr.s_node); 286 memcpy(data, &ddpaddr->sat_port, sizeof(ddpaddr->sat_port)); 287 data += sizeof(ddpaddr->sat_port); 288 } 289#endif /* ! NO_DDP */ 290 291 /* calculate/store Directory Services Names offset */ 292 offset = htons(data - begin); 293 *servoffset += sizeof(offset); 294 memcpy(begin + *servoffset, &offset, sizeof(offset)); 295 296 /* return length of buffer */ 297 return (data - begin); 298} 299 300static size_t status_directorynames(char *data, int *diroffset, 301 const DSI *dsi _U_, 302 const struct afp_options *options) 303{ 304 char *begin = data; 305 u_int16_t offset; 306 memcpy(&offset, data + *diroffset, sizeof(offset)); 307 offset = ntohs(offset); 308 data += offset; 309 310 /* I can not find documentation of any other purpose for the 311 * DirectoryNames field. 312 */ 313 /* 314 * Try to synthesize a principal: 315 * service '/' fqdn '@' realm 316 */ 317 if (options->k5service && options->k5realm && options->fqdn) { 318 /* should k5princ be utf8 encoded? */ 319 size_t len; 320 char *p = strchr( options->fqdn, ':' ); 321 if (p) 322 *p = '\0'; 323 len = strlen( options->k5service ) 324 + strlen( options->fqdn ) 325 + strlen( options->k5realm ); 326 len+=2; /* '/' and '@' */ 327 if ( len > 255 || len+2 > maxstatuslen - offset) { 328 *data++ = 0; 329 LOG ( log_error, logtype_afpd, "status: could not set directory service list, no more room"); 330 } 331 else { 332 *data++ = 1; /* DirectoryNamesCount */ 333 *data++ = len; 334 snprintf( data, len + 1, "%s/%s@%s", options->k5service, 335 options->fqdn, options->k5realm ); 336 data += len; 337 if (p) 338 *p = ':'; 339 } 340 } else { 341 *data++ = 0; 342 } 343 344 /* Calculate and store offset for UTF8ServerName */ 345 *diroffset += sizeof(u_int16_t); 346 offset = htons(data - begin); 347 memcpy(begin + *diroffset, &offset, sizeof(u_int16_t)); 348 349 /* return length of buffer */ 350 return (data - begin); 351} 352 353static size_t status_utf8servername(char *data, int *nameoffset, 354 const DSI *dsi _U_, 355 const struct afp_options *options) 356{ 357 char *Obj, *Type, *Zone; 358 u_int16_t namelen; 359 size_t len; 360 char *begin = data; 361 u_int16_t offset, status; 362 363 memcpy(&offset, data + *nameoffset, sizeof(offset)); 364 offset = ntohs(offset); 365 data += offset; 366 367 /* FIXME: 368 * What is the valid character range for an nbpname? 369 * 370 * Apple's server likes to use the non-qualified hostname 371 * This obviously won't work very well if multiple servers are running 372 * on the box. 373 */ 374 375 /* extract the obj part of the server */ 376 Obj = (char *) (options->server ? options->server : options->hostname); 377 nbp_name(options->server ? options->server : options->hostname, &Obj, &Type, &Zone); 378 379 if ((size_t) -1 == (len = convert_string ( 380 options->unixcharset, CH_UTF8_MAC, 381 Obj, -1, data+sizeof(namelen), maxstatuslen-offset )) ) { 382 LOG ( log_error, logtype_afpd, "Could not set utf8 servername"); 383 384 /* set offset to 0 */ 385 memset(begin + *nameoffset, 0, sizeof(offset)); 386 data = begin + offset; 387 } 388 else { 389 namelen = htons(len); 390 memcpy( data, &namelen, sizeof(namelen)); 391 data += sizeof(namelen); 392 data += len; 393 offset = htons(offset); 394 memcpy(begin + *nameoffset, &offset, sizeof(u_int16_t)); 395 } 396 397 /* return length of buffer */ 398 return (data - begin); 399 400} 401 402/* returns actual offset to signature */ 403static void status_icon(char *data, const unsigned char *icondata, 404 const int iconlen, const int sigoffset) 405{ 406 char *start = data; 407 char *sigdata = data + sigoffset; 408 u_int16_t ret, status; 409 410 memcpy(&status, start + AFPSTATUS_ICONOFF, sizeof(status)); 411 if ( icondata == NULL ) { 412 ret = status; 413 memset(start + AFPSTATUS_ICONOFF, 0, sizeof(status)); 414 } else { 415 data += ntohs( status ); 416 memcpy( data, icondata, iconlen); 417 data += iconlen; 418 ret = htons(data - start); 419 } 420 421 /* put in signature offset */ 422 if (sigoffset) 423 memcpy(sigdata, &ret, sizeof(ret)); 424} 425 426/* --------------------- 427 */ 428void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig, 429 const struct afp_options *options) 430{ 431 ASP asp; 432 DSI *dsi; 433 char *status = NULL; 434 size_t statuslen; 435 int c, sigoff, ipok; 436 437 if (!(aspconfig || dsiconfig) || !options) 438 return; 439 440 if (aspconfig) { 441 status = aspconfig->status; 442 maxstatuslen=sizeof(aspconfig->status); 443 asp = aspconfig->obj.handle; 444 } else 445 asp = NULL; 446 447 ipok = 0; 448 if (dsiconfig) { 449 status = dsiconfig->status; 450 maxstatuslen=sizeof(dsiconfig->status); 451 dsi = dsiconfig->obj.handle; 452 if (dsi->server.ss_family == AF_INET) { /* IPv4 */ 453 const struct sockaddr_in *sa4 = (struct sockaddr_in *)&dsi->server; 454 ipok = sa4->sin_addr.s_addr ? 1 : 0; 455 } else { /* IPv6 */ 456 const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&dsi->server; 457 int i; 458 for (i=0; i<16; i++) { 459 if (sa6->sin6_addr.s6_addr[i]) { 460 ipok = 1; 461 break; 462 } 463 } 464 } 465 } else 466 dsi = NULL; 467 468 /* 469 * These routines must be called in order -- earlier calls 470 * set the offsets for later calls. 471 * 472 * using structs is a bad idea, but that's what the original code 473 * does. solaris, in fact, will segfault with them. so, now 474 * we just use the powers of #defines and memcpy. 475 * 476 * reply block layout (offsets are 16-bit quantities): 477 * machine type offset -> AFP version count offset -> 478 * UAM count offset -> vol icon/mask offset -> flags -> 479 * 480 * server name [padded to even boundary] -> signature offset -> 481 * network address offset -> 482 * 483 * at the appropriate offsets: 484 * machine type, afp versions, uams, server signature 485 * (16-bytes), network addresses, volume icon/mask 486 */ 487 488 status_flags(status, 489 options->server_notif, 490 (options->fqdn || ipok), 491 options->passwdbits, 492 (options->k5service && options->k5realm && options->fqdn), 493 options->flags); 494 /* returns offset to signature offset */ 495 c = status_server(status, options->server ? options->server : 496 options->hostname, options); 497 status_machine(status); 498 status_versions(status, asp, dsi); 499 status_uams(status, options->uamlist); 500 if (options->flags & OPTION_CUSTOMICON) 501 status_icon(status, icon, sizeof(icon), c); 502 else 503 status_icon(status, apple_atalk_icon, sizeof(apple_atalk_icon), c); 504 505 sigoff = status_signature(status, &c, options); 506 /* c now contains the offset where the netaddress offset lives */ 507 508 status_netaddress(status, &c, asp, dsi, options); 509 /* c now contains the offset where the Directory Names Count offset lives */ 510 511 statuslen = status_directorynames(status, &c, dsi, options); 512 /* c now contains the offset where the UTF-8 ServerName offset lives */ 513 514 if ( statuslen < maxstatuslen) 515 statuslen = status_utf8servername(status, &c, dsi, options); 516 517#ifndef NO_DDP 518 if (aspconfig) { 519 if (dsiconfig) /* status is dsiconfig->status */ 520 memcpy(aspconfig->status, status, statuslen); 521 asp_setstatus(asp, status, statuslen); 522 aspconfig->signature = status + sigoff; 523 aspconfig->statuslen = statuslen; 524 } 525#endif /* ! NO_DDP */ 526 527 if (dsiconfig) { 528 if ((options->flags & OPTION_CUSTOMICON) == 0) { 529 status_icon(status, apple_tcp_icon, sizeof(apple_tcp_icon), 0); 530 } 531 dsi_setstatus(dsi, status, statuslen); 532 dsiconfig->signature = status + sigoff; 533 dsiconfig->statuslen = statuslen; 534 } 535} 536 537/* set_signature() */ 538/* */ 539/* If found in conf file, use it. */ 540/* If not found in conf file, genarate and append in conf file. */ 541/* If conf file don't exist, create and genarate. */ 542/* If cannot open conf file, use one-time signature. */ 543/* If -signature user:xxxxx, use it. */ 544 545void set_signature(struct afp_options *options) { 546 char *usersign; 547 int fd, i; 548 struct stat tmpstat; 549 char *servername_conf; 550 int header = 0; 551 char buf[1024], *p; 552 FILE *fp = NULL, *randomp; 553 size_t len; 554 char *server_tmp; 555 556 server_tmp = (options->server ? options->server : options->hostname); 557 if (strcmp(options->signatureopt, "auto") == 0) { 558 goto server_signature_auto; /* default */ 559 } else if (strcmp(options->signatureopt, "host") == 0) { 560 LOG(log_warning, logtype_afpd, "WARNING: option \"-signature host\" is obsoleted. Switching back to auto.", options->signatureopt); 561 goto server_signature_auto; /* same as auto */ 562 } else if (strncmp(options->signatureopt, "user", 4) == 0) { 563 goto server_signature_user; /* user string */ 564 } else { 565 LOG(log_error, logtype_afpd, "ERROR: option \"-signature %s\" is not valid. Switching back to auto.", options->signatureopt); 566 goto server_signature_auto; /* switch back to auto*/ 567 } 568 569server_signature_user: 570 571 /* Signature type is user string */ 572 len = strlen(options->signatureopt); 573 if (len <= 5) { 574 LOG(log_warning, logtype_afpd, "WARNING: option \"-signature %s\" is not valid. Switching back to auto.", options->signatureopt); 575 goto server_signature_auto; 576 } 577 usersign = options->signatureopt + 5; 578 len = len - 5; 579 if (len > 16) { 580 LOG(log_warning, logtype_afpd, "WARNING: signature user string %s is very long !", usersign); 581 len = 16; 582 } else if (len >= 3) { 583 LOG(log_info, logtype_afpd, "signature user string is %s.", usersign); 584 } else { 585 LOG(log_warning, logtype_afpd, "WARNING: signature user string %s is very short !", usersign); 586 } 587 memset(options->signature, 0, 16); 588 memcpy(options->signature, usersign, len); 589 goto server_signature_done; 590 591server_signature_auto: 592 593 /* Signature type is auto, using afp_signature.conf */ 594 if (!stat(options->sigconffile, &tmpstat)) { /* conf file exists? */ 595 if ((fp = fopen(options->sigconffile, "r")) != NULL) { /* read open? */ 596 /* scan in the conf file */ 597 while (fgets(buf, sizeof(buf), fp) != NULL) { 598 p = buf; 599 while (p && isblank(*p)) 600 p++; 601 if (!p || (*p == '#') || (*p == '\n')) 602 continue; /* invalid line */ 603 if (*p == '"') { 604 p++; 605 if ((servername_conf = strtok( p, "\"" )) == NULL) 606 continue; /* syntax error: invalid quoted servername */ 607 } else { 608 if ((servername_conf = strtok( p, " \t" )) == NULL) 609 continue; /* syntax error: invalid servername */ 610 } 611 p = strchr(p, '\0'); 612 p++; 613 if (*p == '\0') 614 continue; /* syntax error: missing signature */ 615 616 if (strcmp(server_tmp, servername_conf)) 617 continue; /* another servername */ 618 619 while (p && isblank(*p)) 620 p++; 621 if ( 16 == sscanf(p, "%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX%2hhX", 622 &options->signature[ 0], &options->signature[ 1], 623 &options->signature[ 2], &options->signature[ 3], 624 &options->signature[ 4], &options->signature[ 5], 625 &options->signature[ 6], &options->signature[ 7], 626 &options->signature[ 8], &options->signature[ 9], 627 &options->signature[10], &options->signature[11], 628 &options->signature[12], &options->signature[13], 629 &options->signature[14], &options->signature[15] 630 )) { 631 fclose(fp); 632 goto server_signature_done; /* found in conf file */ 633 } 634 } 635 if ((fp = freopen(options->sigconffile, "a+", fp)) != NULL) { /* append because not found */ 636 fseek(fp, 0L, SEEK_END); 637 if(ftell(fp) == 0) { /* size = 0 */ 638 header = 1; 639 goto server_signature_random; 640 } else { 641 fseek(fp, -1L, SEEK_END); 642 if(fgetc(fp) != '\n') fputc('\n', fp); /* last char is \n? */ 643 goto server_signature_random; 644 } 645 } else { 646 LOG(log_error, logtype_afpd, "ERROR: Cannot write in %s (%s). Using one-time signature.", 647 options->sigconffile, strerror(errno)); 648 goto server_signature_random; 649 } 650 } else { 651 LOG(log_error, logtype_afpd, "ERROR: Cannot read %s (%s). Using one-time signature.", 652 options->sigconffile, strerror(errno)); 653 goto server_signature_random; 654 } 655 } else { /* conf file don't exist */ 656 if (( fd = creat(options->sigconffile, 0644 )) < 0 ) { 657 LOG(log_error, logtype_afpd, "ERROR: Cannot create %s (%s). Using one-time signature.", 658 options->sigconffile, strerror(errno)); 659 goto server_signature_random; 660 } 661 if (( fp = fdopen( fd, "w" )) == NULL ) { 662 LOG(log_error, logtype_afpd, "ERROR: Cannot fdopen %s (%s). Using one-time signature.", 663 options->sigconffile, strerror(errno)); 664 close(fd); 665 goto server_signature_random; 666 } 667 header = 1; 668 goto server_signature_random; 669 } 670 671server_signature_random: 672 673 /* generate signature from random number */ 674 randombytes(options->signature, 16); 675 676 if (fp && header) { /* conf file is created or size=0 */ 677 fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n"); 678 fprintf(fp, "# This file is auto-generated by afpd.\n"); 679 fprintf(fp, "# \n"); 680 fprintf(fp, "# ServerSignature is unique identifier used to prevent logging on to\n"); 681 fprintf(fp, "# the same server twice.\n"); 682 fprintf(fp, "# \n"); 683 fprintf(fp, "# If setting \"-signature user:xxxxx\" in afpd.conf, this file is not used.\n\n"); 684 } 685 686 if (fp) { 687 fprintf(fp, "\"%s\"\t", server_tmp); 688 for (i=0 ; i<16 ; i++) { 689 fprintf(fp, "%02X", (options->signature)[i]); 690 } 691 fprintf(fp, "%s", "\n"); 692 fclose(fp); 693 } 694 695server_signature_done: 696 697 /* retrun */ 698 LOG(log_info, logtype_afpd, 699 " \"%s\"'s signature is %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", 700 server_tmp, 701 (options->signature)[ 0], (options->signature)[ 1], 702 (options->signature)[ 2], (options->signature)[ 3], 703 (options->signature)[ 4], (options->signature)[ 5], 704 (options->signature)[ 6], (options->signature)[ 7], 705 (options->signature)[ 8], (options->signature)[ 9], 706 (options->signature)[10], (options->signature)[11], 707 (options->signature)[12], (options->signature)[13], 708 (options->signature)[14], (options->signature)[15]); 709 710 return; 711} 712 713/* this is the same as asp/dsi_getstatus */ 714int afp_getsrvrinfo(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) 715{ 716 AFPConfig *config = obj->config; 717 718 memcpy(rbuf, config->status, config->statuslen); 719 *rbuflen = config->statuslen; 720 return AFP_OK; 721} 722