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