1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <assert.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <arpa/nameser.h> 36 #include <net/if.h> 37 #include <resolv.h> 38 #include <sys/time.h> 39 #include <unistd.h> 40 #include <string.h> 41 #include <pthread.h> 42 #include <netdb.h> 43 #include <rpc/rpc.h> 44 #include <syslog.h> 45 #include <gssapi/gssapi.h> 46 #include <kerberosv5/krb5.h> 47 48 #include <smbns_dyndns.h> 49 #include <smbns_krb.h> 50 51 /* 52 * The following can be removed once head/arpa/nameser_compat.h 53 * defines BADSIG, BADKEY and BADTIME. 54 */ 55 #ifndef BADSIG 56 #define BADSIG ns_r_badsig 57 #endif /* BADSIG */ 58 59 #ifndef BADKEY 60 #define BADKEY ns_r_badkey 61 #endif /* BADKEY */ 62 63 #ifndef BADTIME 64 #define BADTIME ns_r_badtime 65 #endif /* BADTIME */ 66 67 /* internal use, in dyndns_add_entry */ 68 #define DEL_NONE 2 69 70 /* Maximum retires if not authoritative */ 71 #define MAX_AUTH_RETRIES 3 72 73 /* Number of times to retry a DNS query */ 74 #define DYNDNS_MAX_QUERY_RETRIES 3 75 76 /* Timeout value, in seconds, for DNS query responses */ 77 #define DYNDNS_QUERY_TIMEOUT 2 78 79 static uint16_t dns_msgid; 80 mutex_t dns_msgid_mtx; 81 82 #define DYNDNS_OP_CLEAR 1 83 #define DYNDNS_OP_UPDATE 2 84 85 #define DYNDNS_STATE_INIT 0 86 #define DYNDNS_STATE_READY 1 87 #define DYNDNS_STATE_PUBLISHING 2 88 #define DYNDNS_STATE_STOPPING 3 89 90 typedef struct dyndns_qentry { 91 list_node_t dqe_lnd; 92 int dqe_op; 93 char dqe_fqdn[MAXHOSTNAMELEN]; 94 } dyndns_qentry_t; 95 96 typedef struct dyndns_queue { 97 list_t ddq_list; 98 mutex_t ddq_mtx; 99 cond_t ddq_cv; 100 uint32_t ddq_state; 101 } dyndns_queue_t; 102 103 static dyndns_queue_t dyndns_queue; 104 105 static void dyndns_queue_request(int, const char *); 106 static void dyndns_queue_flush(list_t *); 107 static void *dyndns_publisher(void *); 108 static void dyndns_process(list_t *); 109 static int dyndns_update_core(char *); 110 static int dyndns_clear_rev_zone(char *); 111 static void dyndns_msgid_init(void); 112 static int dyndns_get_msgid(void); 113 static void dyndns_syslog(int, int, const char *); 114 115 int 116 dyndns_start(void) 117 { 118 pthread_t publisher; 119 pthread_attr_t tattr; 120 int rc; 121 122 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 123 return (0); 124 125 (void) mutex_lock(&dyndns_queue.ddq_mtx); 126 if (dyndns_queue.ddq_state != DYNDNS_STATE_INIT) { 127 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 128 return (0); 129 } 130 131 dyndns_msgid_init(); 132 133 list_create(&dyndns_queue.ddq_list, sizeof (dyndns_qentry_t), 134 offsetof(dyndns_qentry_t, dqe_lnd)); 135 dyndns_queue.ddq_state = DYNDNS_STATE_READY; 136 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 137 138 (void) pthread_attr_init(&tattr); 139 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 140 rc = pthread_create(&publisher, &tattr, dyndns_publisher, 0); 141 (void) pthread_attr_destroy(&tattr); 142 return (rc); 143 } 144 145 void 146 dyndns_stop(void) 147 { 148 (void) mutex_lock(&dyndns_queue.ddq_mtx); 149 150 switch (dyndns_queue.ddq_state) { 151 case DYNDNS_STATE_READY: 152 case DYNDNS_STATE_PUBLISHING: 153 dyndns_queue.ddq_state = DYNDNS_STATE_STOPPING; 154 (void) cond_signal(&dyndns_queue.ddq_cv); 155 break; 156 default: 157 break; 158 } 159 160 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 161 } 162 163 /* 164 * Clear all records in both zones. 165 */ 166 void 167 dyndns_clear_zones(void) 168 { 169 char fqdn[MAXHOSTNAMELEN]; 170 171 if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) != 0) { 172 syslog(LOG_ERR, "dyndns: failed to get domainname"); 173 return; 174 } 175 176 dyndns_queue_request(DYNDNS_OP_CLEAR, fqdn); 177 } 178 179 /* 180 * Update all records in both zones. 181 */ 182 void 183 dyndns_update_zones(void) 184 { 185 char fqdn[MAXHOSTNAMELEN]; 186 187 if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) != 0) { 188 syslog(LOG_ERR, "dyndns: failed to get domainname"); 189 return; 190 } 191 192 dyndns_queue_request(DYNDNS_OP_UPDATE, fqdn); 193 } 194 195 /* 196 * Add a request to the queue. 197 */ 198 static void 199 dyndns_queue_request(int op, const char *fqdn) 200 { 201 dyndns_qentry_t *entry; 202 203 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 204 return; 205 206 (void) mutex_lock(&dyndns_queue.ddq_mtx); 207 208 switch (dyndns_queue.ddq_state) { 209 case DYNDNS_STATE_READY: 210 case DYNDNS_STATE_PUBLISHING: 211 break; 212 default: 213 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 214 return; 215 } 216 217 if ((entry = malloc(sizeof (dyndns_qentry_t))) == NULL) { 218 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 219 return; 220 } 221 222 bzero(entry, sizeof (dyndns_qentry_t)); 223 entry->dqe_op = op; 224 (void) strlcpy(entry->dqe_fqdn, fqdn, MAXNAMELEN); 225 226 list_insert_tail(&dyndns_queue.ddq_list, entry); 227 (void) cond_signal(&dyndns_queue.ddq_cv); 228 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 229 } 230 231 /* 232 * Flush all remaining items from the specified list/queue. 233 */ 234 static void 235 dyndns_queue_flush(list_t *lst) 236 { 237 dyndns_qentry_t *entry; 238 239 while ((entry = list_head(lst)) != NULL) { 240 list_remove(lst, entry); 241 free(entry); 242 } 243 } 244 245 /* 246 * Dyndns update thread. While running, the thread waits on a condition 247 * variable until notified that an entry needs to be updated. 248 * 249 * If the outgoing queue is not empty, the thread wakes up every 60 seconds 250 * to retry. 251 */ 252 /*ARGSUSED*/ 253 static void * 254 dyndns_publisher(void *arg) 255 { 256 dyndns_qentry_t *entry; 257 list_t publist; 258 259 (void) mutex_lock(&dyndns_queue.ddq_mtx); 260 if (dyndns_queue.ddq_state != DYNDNS_STATE_READY) { 261 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 262 return (NULL); 263 } 264 dyndns_queue.ddq_state = DYNDNS_STATE_PUBLISHING; 265 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 266 267 list_create(&publist, sizeof (dyndns_qentry_t), 268 offsetof(dyndns_qentry_t, dqe_lnd)); 269 270 for (;;) { 271 (void) mutex_lock(&dyndns_queue.ddq_mtx); 272 273 while (list_is_empty(&dyndns_queue.ddq_list) && 274 (dyndns_queue.ddq_state == DYNDNS_STATE_PUBLISHING)) { 275 (void) cond_wait(&dyndns_queue.ddq_cv, 276 &dyndns_queue.ddq_mtx); 277 } 278 279 if (dyndns_queue.ddq_state != DYNDNS_STATE_PUBLISHING) { 280 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 281 break; 282 } 283 284 /* 285 * Transfer queued items to the local list so that 286 * the mutex can be released. 287 */ 288 while ((entry = list_head(&dyndns_queue.ddq_list)) != NULL) { 289 list_remove(&dyndns_queue.ddq_list, entry); 290 list_insert_tail(&publist, entry); 291 } 292 293 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 294 295 dyndns_process(&publist); 296 } 297 298 (void) mutex_lock(&dyndns_queue.ddq_mtx); 299 dyndns_queue_flush(&dyndns_queue.ddq_list); 300 list_destroy(&dyndns_queue.ddq_list); 301 dyndns_queue.ddq_state = DYNDNS_STATE_INIT; 302 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 303 304 dyndns_queue_flush(&publist); 305 list_destroy(&publist); 306 return (NULL); 307 } 308 309 /* 310 * Remove items from the queue and process them. 311 */ 312 static void 313 dyndns_process(list_t *publist) 314 { 315 dyndns_qentry_t *entry; 316 317 while ((entry = list_head(publist)) != NULL) { 318 (void) mutex_lock(&dyndns_queue.ddq_mtx); 319 if (dyndns_queue.ddq_state != DYNDNS_STATE_PUBLISHING) { 320 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 321 dyndns_queue_flush(publist); 322 return; 323 } 324 (void) mutex_unlock(&dyndns_queue.ddq_mtx); 325 326 list_remove(publist, entry); 327 328 switch (entry->dqe_op) { 329 case DYNDNS_OP_CLEAR: 330 (void) dyndns_clear_rev_zone(entry->dqe_fqdn); 331 break; 332 case DYNDNS_OP_UPDATE: 333 (void) dyndns_update_core(entry->dqe_fqdn); 334 break; 335 default: 336 break; 337 } 338 339 free(entry); 340 } 341 } 342 343 /* 344 * Dynamic DNS update API for kclient. 345 * 346 * Returns 0 upon success. Otherwise, returns -1. 347 */ 348 int 349 dyndns_update(char *fqdn) 350 { 351 int rc; 352 353 if (smb_nic_init() != 0) 354 return (-1); 355 356 dyndns_msgid_init(); 357 rc = dyndns_update_core(fqdn); 358 smb_nic_fini(); 359 return (rc); 360 } 361 362 /* 363 * Initializes the DNS message ID counter using the algorithm 364 * that resolver library uses to initialize the ID field of any res 365 * structure. 366 */ 367 static void 368 dyndns_msgid_init(void) 369 { 370 struct timeval now; 371 372 (void) gettimeofday(&now, NULL); 373 (void) mutex_lock(&dns_msgid_mtx); 374 dns_msgid = (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); 375 (void) mutex_unlock(&dns_msgid_mtx); 376 } 377 378 static int 379 dyndns_get_msgid(void) 380 { 381 uint16_t id; 382 383 (void) mutex_lock(&dns_msgid_mtx); 384 id = ++dns_msgid; 385 (void) mutex_unlock(&dns_msgid_mtx); 386 return (id); 387 } 388 389 /* 390 * Log a DNS error message 391 */ 392 static void 393 dyndns_syslog(int severity, int errnum, const char *text) 394 { 395 struct { 396 int errnum; 397 char *errmsg; 398 } errtab[] = { 399 { FORMERR, "message format error" }, 400 { SERVFAIL, "server internal error" }, 401 { NXDOMAIN, "entry should exist but does not exist" }, 402 { NOTIMP, "not supported" }, 403 { REFUSED, "operation refused" }, 404 { YXDOMAIN, "entry should not exist but does exist" }, 405 { YXRRSET, "RRSet should not exist but does exist" }, 406 { NXRRSET, "RRSet should exist but does not exist" }, 407 { NOTAUTH, "server is not authoritative for specified zone" }, 408 { NOTZONE, "name not within specified zone" }, 409 { BADSIG, "bad transaction signature (TSIG)" }, 410 { BADKEY, "bad transaction key (TKEY)" }, 411 { BADTIME, "time not synchronized" }, 412 }; 413 414 char *errmsg = "unknown error"; 415 int i; 416 417 if (errnum == NOERROR) 418 return; 419 420 for (i = 0; i < (sizeof (errtab) / sizeof (errtab[0])); ++i) { 421 if (errtab[i].errnum == errnum) { 422 errmsg = errtab[i].errmsg; 423 break; 424 } 425 } 426 427 syslog(severity, "dyndns: %s: %s: %d", text, errmsg, errnum); 428 } 429 430 /* 431 * display_stat 432 * Display GSS error message from error code. This routine is used to display 433 * the mechanism independent and mechanism specific error messages for GSS 434 * routines. The major status error code is the mechanism independent error 435 * code and the minor status error code is the mechanism specific error code. 436 * Parameters: 437 * maj: GSS major status 438 * min: GSS minor status 439 * Returns: 440 * None 441 */ 442 static void 443 display_stat(OM_uint32 maj, OM_uint32 min) 444 { 445 gss_buffer_desc msg; 446 OM_uint32 msg_ctx = 0; 447 OM_uint32 min2; 448 449 (void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, 450 &msg_ctx, &msg); 451 syslog(LOG_ERR, "dyndns: GSS major status error: %s", 452 (char *)msg.value); 453 (void) gss_release_buffer(&min2, &msg); 454 455 (void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, 456 &msg_ctx, &msg); 457 syslog(LOG_ERR, "dyndns: GSS minor status error: %s", 458 (char *)msg.value); 459 (void) gss_release_buffer(&min2, &msg); 460 } 461 462 static char * 463 dyndns_put_nshort(char *buf, uint16_t val) 464 { 465 uint16_t nval; 466 467 nval = htons(val); 468 (void) memcpy(buf, &nval, sizeof (uint16_t)); 469 buf += sizeof (uint16_t); 470 return (buf); 471 } 472 473 static char * 474 dyndns_get_nshort(char *buf, uint16_t *val) 475 { 476 uint16_t nval; 477 478 (void) memcpy(&nval, buf, sizeof (uint16_t)); 479 *val = ntohs(nval); 480 buf += sizeof (uint16_t); 481 return (buf); 482 } 483 484 static char * 485 dyndns_put_nlong(char *buf, uint32_t val) 486 { 487 uint32_t lval; 488 489 lval = htonl(val); 490 (void) memcpy(buf, &lval, sizeof (uint32_t)); 491 buf += sizeof (uint32_t); 492 return (buf); 493 } 494 495 static char * 496 dyndns_put_byte(char *buf, char val) 497 { 498 *buf = val; 499 buf++; 500 return (buf); 501 } 502 503 static char * 504 dyndns_put_int(char *buf, int val) 505 { 506 (void) memcpy(buf, &val, sizeof (int)); 507 buf += sizeof (int); 508 return (buf); 509 } 510 511 /* 512 * dyndns_stuff_str 513 * Converts a domain string by removing periods and replacing with a byte value 514 * of how many characters following period. A byte value is placed in front 515 * to indicate how many characters before first period. A NULL character is 516 * placed at the end. i.e. host.procom.com -> 4host5procom3com0 517 * Buffer space checking is done by caller. 518 * Parameters: 519 * ptr : address of pointer to buffer to store converted string 520 * zone: domain name string 521 * Returns: 522 * ptr: address of pointer to next available buffer space 523 * -1 : error 524 * 0 : success 525 */ 526 static int 527 dyndns_stuff_str(char **ptr, char *zone) 528 { 529 int len; 530 char *lenPtr, *zonePtr; 531 532 for (zonePtr = zone; *zonePtr; ) { 533 lenPtr = *ptr; 534 *ptr = *ptr + 1; 535 len = 0; 536 while (*zonePtr != '.' && *zonePtr != 0) { 537 *ptr = dyndns_put_byte(*ptr, *zonePtr); 538 zonePtr++; 539 len++; 540 } 541 *lenPtr = len; 542 if (*zonePtr == '.') 543 zonePtr++; 544 } 545 *ptr = dyndns_put_byte(*ptr, 0); 546 return (0); 547 } 548 549 /* 550 * dyndns_build_header 551 * Build the header for DNS query and DNS update request message. 552 * Parameters: 553 * ptr : address of pointer to buffer to store header 554 * buf_len : buffer length 555 * msg_id : message id 556 * query_req : use REQ_QUERY for query message or REQ_UPDATE for 557 * update message 558 * quest_zone_cnt : number of question record for query message or 559 * number of zone record for update message 560 * ans_prereq_cnt : number of answer record for query message or 561 * number of prerequisite record for update message 562 * nameser_update_cnt: number of name server for query message or 563 * number of update record for update message 564 * addit_cnt : number of additional record 565 * flags : query flags word 566 * Returns: 567 * ptr: address of pointer to next available buffer space 568 * -1 : error 569 * 0 : success 570 */ 571 static int 572 dyndns_build_header(char **ptr, int buf_len, uint16_t msg_id, int query_req, 573 uint16_t quest_zone_cnt, uint16_t ans_prereq_cnt, 574 uint16_t nameser_update_cnt, uint16_t addit_cnt, int flags) 575 { 576 uint16_t opcode; 577 578 if (buf_len < 12) { 579 syslog(LOG_ERR, "dyndns header section: buffer too small"); 580 return (-1); 581 } 582 583 *ptr = dyndns_put_nshort(*ptr, msg_id); /* mesg ID */ 584 if (query_req == REQ_QUERY) 585 opcode = ns_o_query; /* query msg */ 586 else 587 opcode = ns_o_update << 11; /* update msg */ 588 opcode |= flags; 589 /* mesg opcode */ 590 *ptr = dyndns_put_nshort(*ptr, opcode); 591 /* zone record count */ 592 *ptr = dyndns_put_nshort(*ptr, quest_zone_cnt); 593 /* prerequiste record count */ 594 *ptr = dyndns_put_nshort(*ptr, ans_prereq_cnt); 595 /* update record count */ 596 *ptr = dyndns_put_nshort(*ptr, nameser_update_cnt); 597 /* additional record count */ 598 *ptr = dyndns_put_nshort(*ptr, addit_cnt); 599 600 return (0); 601 } 602 603 /* 604 * dyndns_build_quest_zone 605 * Build the question section for query message or zone section for 606 * update message. 607 * Parameters: 608 * ptr : address of pointer to buffer to store question or zone section 609 * buf_len: buffer length 610 * name : question or zone name 611 * type : type of question or zone 612 * class : class of question or zone 613 * Returns: 614 * ptr: address of pointer to next available buffer space 615 * -1 : error 616 * 0 : success 617 */ 618 static int 619 dyndns_build_quest_zone(char **ptr, int buf_len, char *name, int type, 620 int class) 621 { 622 char *zonePtr; 623 624 if ((strlen(name) + 6) > buf_len) { 625 syslog(LOG_ERR, "dyndns question section: buffer too small"); 626 return (-1); 627 } 628 629 zonePtr = *ptr; 630 (void) dyndns_stuff_str(&zonePtr, name); 631 *ptr = zonePtr; 632 *ptr = dyndns_put_nshort(*ptr, type); 633 *ptr = dyndns_put_nshort(*ptr, class); 634 return (0); 635 } 636 637 /* 638 * dyndns_build_update 639 * Build update section of update message for adding and removing a record. 640 * If the ttl value is 0 then this message is for record deletion. 641 * 642 * Parameters: 643 * ptr : address of pointer to buffer to store update section 644 * buf_len : buffer length 645 * name : resource name of this record 646 * type : type of this record 647 * class : class of this record 648 * ttl : time-to-live, cached time of this entry by others and not 649 * within DNS database, a zero value for record(s) deletion 650 * data : data of this resource record 651 * forw_rev: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 652 * add_del : UPDATE_ADD for adding entry, UPDATE_DEL for removing zone 653 * del_type: DEL_ONE for deleting one entry, DEL_ALL for deleting all 654 * entries of the same resource name. Only valid for UPDATE_DEL. 655 * Returns: 656 * ptr: address of pointer to next available buffer space 657 * -1 : error 658 * 0 : success 659 */ 660 static int 661 dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class, 662 uint32_t ttl, char *data, int forw_rev, int add_del, int del_type) 663 { 664 char *namePtr; 665 int rec_len, data_len; 666 667 rec_len = strlen(name) + 10; 668 if (add_del == UPDATE_ADD) { 669 if (forw_rev == UPDATE_FORW) 670 data_len = 4; 671 else 672 data_len = strlen(data) + 2; 673 } else { 674 if (del_type == DEL_ALL) 675 data_len = 0; 676 else if (forw_rev == UPDATE_FORW) 677 data_len = 4; 678 else 679 data_len = strlen(data) + 2; 680 } 681 682 if (rec_len + data_len > buf_len) { 683 syslog(LOG_ERR, "dyndns update section: buffer too small"); 684 return (-1); 685 } 686 687 namePtr = *ptr; 688 (void) dyndns_stuff_str(&namePtr, name); 689 *ptr = namePtr; 690 *ptr = dyndns_put_nshort(*ptr, type); 691 *ptr = dyndns_put_nshort(*ptr, class); 692 *ptr = dyndns_put_nlong(*ptr, ttl); 693 694 if (add_del == UPDATE_DEL && del_type == DEL_ALL) { 695 *ptr = dyndns_put_nshort(*ptr, 0); 696 return (0); 697 } 698 699 if (forw_rev == UPDATE_FORW) { 700 *ptr = dyndns_put_nshort(*ptr, 4); 701 *ptr = dyndns_put_int(*ptr, inet_addr(data)); /* ip address */ 702 } else { 703 *ptr = dyndns_put_nshort(*ptr, strlen(data)+2); 704 namePtr = *ptr; 705 (void) dyndns_stuff_str(&namePtr, data); /* hostname */ 706 *ptr = namePtr; 707 } 708 return (0); 709 } 710 711 /* 712 * dyndns_build_tkey 713 * Build TKEY section to establish security context for secure dynamic DNS 714 * update. DNS header and question sections need to be build before this 715 * section. The TKEY data are the tokens generated during security context 716 * establishment and the TKEY message is used to transmit those tokens, one 717 * at a time, to the DNS server. 718 * Parameters: 719 * ptr : address of pointer to buffer to store TKEY 720 * buf_len : buffer length 721 * name : key name, must be unique and same as for TSIG record 722 * key_expire: expiration time of this key in second 723 * data : TKEY data 724 * data_size : data size 725 * Returns: 726 * ptr: address of the pointer to the next available buffer space 727 * -1 : error 728 * 0 : success 729 */ 730 static int 731 dyndns_build_tkey(char **ptr, int buf_len, char *name, int key_expire, 732 char *data, int data_size) 733 { 734 char *namePtr; 735 struct timeval tp; 736 737 if (strlen(name)+2 + 45 + data_size > buf_len) { 738 syslog(LOG_ERR, "dyndns TKEY: buffer too small"); 739 return (-1); 740 } 741 742 namePtr = *ptr; 743 (void) dyndns_stuff_str(&namePtr, name); /* unique global name */ 744 *ptr = namePtr; 745 *ptr = dyndns_put_nshort(*ptr, ns_t_tkey); 746 *ptr = dyndns_put_nshort(*ptr, ns_c_any); 747 *ptr = dyndns_put_nlong(*ptr, 0); 748 /* 19 + 14 + data_size + 2 */ 749 *ptr = dyndns_put_nshort(*ptr, 35 + data_size); 750 namePtr = *ptr; 751 (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com"); 752 *ptr = namePtr; 753 (void) gettimeofday(&tp, 0); 754 *ptr = dyndns_put_nlong(*ptr, tp.tv_sec); /* inception */ 755 /* expiration, 86400 */ 756 *ptr = dyndns_put_nlong(*ptr, tp.tv_sec + key_expire); 757 *ptr = dyndns_put_nshort(*ptr, MODE_GSS_API); /* mode: gss-api */ 758 *ptr = dyndns_put_nshort(*ptr, 0); /* error */ 759 *ptr = dyndns_put_nshort(*ptr, data_size); /* key size */ 760 (void) memcpy(*ptr, data, data_size); /* key data */ 761 *ptr += data_size; 762 *ptr = dyndns_put_nshort(*ptr, 0); /* other */ 763 return (0); 764 } 765 766 /* 767 * dyndns_build_tsig 768 * Build TSIG section for secure dynamic DNS update. This routine will be 769 * called twice. First called with TSIG_UNSIGNED, and second with TSIG_SIGNED. 770 * The TSIG data is NULL and ignored for TSIG_UNSIGNED and is the update request 771 * message encrypted for TSIG_SIGNED. The message id must be the same id as the 772 * one in the update request before it is encrypted. 773 * Parameters: 774 * ptr : address of pointer to buffer to store TSIG 775 * buf_len : buffer length 776 * msg_id : message id 777 * name : key name, must be the same as in TKEY record 778 * fudge_time : amount of error time allow in seconds 779 * data : TSIG data if TSIG_SIGNED, otherwise NULL 780 * data_size : size of data, otherwise 0 if data is NULL 781 * data_signed: TSIG_SIGNED to indicate data is signed and encrypted, 782 * otherwise TSIG_UNSIGNED 783 * Returns: 784 * ptr: address of pointer to next available buffer space 785 * -1 : error 786 * 0 : success 787 */ 788 static int 789 dyndns_build_tsig(char **ptr, int buf_len, int msg_id, char *name, 790 int fudge_time, char *data, int data_size, int data_signed) 791 { 792 char *namePtr; 793 struct timeval tp; 794 int signtime, fudge, rec_len; 795 796 if (data_signed == TSIG_UNSIGNED) 797 rec_len = strlen(name)+2 + 37; 798 else 799 rec_len = strlen(name)+2 + 45 + data_size; 800 801 if (rec_len > buf_len) { 802 syslog(LOG_ERR, "dyndns TSIG: buffer too small"); 803 return (-1); 804 } 805 806 namePtr = *ptr; 807 (void) dyndns_stuff_str(&namePtr, name); /* unique global name */ 808 *ptr = namePtr; 809 if (data_signed == TSIG_SIGNED) 810 *ptr = dyndns_put_nshort(*ptr, ns_t_tsig); 811 *ptr = dyndns_put_nshort(*ptr, ns_c_any); 812 *ptr = dyndns_put_nlong(*ptr, 0); 813 if (data_signed == TSIG_SIGNED) { 814 /* 19 + 10 + data_size + 6 */ 815 *ptr = dyndns_put_nshort(*ptr, 35 + data_size); 816 } 817 namePtr = *ptr; 818 (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com"); 819 *ptr = namePtr; 820 (void) gettimeofday(&tp, 0); 821 signtime = tp.tv_sec >> 16; 822 *ptr = dyndns_put_nlong(*ptr, signtime); /* sign time */ 823 fudge = tp.tv_sec << 16; 824 fudge |= fudge_time; 825 *ptr = dyndns_put_nlong(*ptr, fudge); /* fudge time */ 826 if (data_signed == TSIG_SIGNED) { 827 /* signed data size */ 828 *ptr = dyndns_put_nshort(*ptr, data_size); 829 (void) memcpy(*ptr, data, data_size); /* signed data */ 830 *ptr += data_size; 831 *ptr = dyndns_put_nshort(*ptr, msg_id); /* original id */ 832 } 833 *ptr = dyndns_put_nshort(*ptr, 0); /* error */ 834 *ptr = dyndns_put_nshort(*ptr, 0); /* other */ 835 return (0); 836 } 837 838 /* 839 * dyndns_open_init_socket 840 * This routine creates a SOCK_STREAM or SOCK_DGRAM socket and initializes it 841 * by doing bind() and setting linger option to off. 842 * 843 * Parameters: 844 * sock_type: SOCK_STREAM for TCP or SOCK_DGRAM for UDP 845 * dest_addr: destination address in network byte order 846 * port : destination port number 847 * Returns: 848 * descriptor: descriptor referencing the created socket 849 * -1 : error 850 */ 851 static int 852 dyndns_open_init_socket(int sock_type, unsigned long dest_addr, int port) 853 { 854 int s; 855 struct sockaddr_in my_addr; 856 struct linger l; 857 struct sockaddr_in serv_addr; 858 859 if ((s = socket(AF_INET, sock_type, 0)) == -1) { 860 syslog(LOG_ERR, "dyndns: socket error"); 861 return (-1); 862 } 863 864 l.l_onoff = 0; 865 if (setsockopt(s, SOL_SOCKET, SO_LINGER, 866 (char *)&l, sizeof (l)) == -1) { 867 syslog(LOG_ERR, "dyndns: setsockopt error"); 868 (void) close(s); 869 return (-1); 870 } 871 872 bzero(&my_addr, sizeof (my_addr)); 873 my_addr.sin_family = AF_INET; 874 my_addr.sin_port = htons(0); 875 my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 876 877 if (bind(s, (struct sockaddr *)&my_addr, sizeof (my_addr)) < 0) { 878 syslog(LOG_ERR, "dyndns: client bind error"); 879 (void) close(s); 880 return (-1); 881 } 882 883 serv_addr.sin_family = AF_INET; 884 serv_addr.sin_port = htons(port); 885 serv_addr.sin_addr.s_addr = dest_addr; 886 887 if (connect(s, (struct sockaddr *)&serv_addr, 888 sizeof (struct sockaddr_in)) < 0) { 889 syslog(LOG_ERR, "dyndns: client connect error (%s)", 890 strerror(errno)); 891 (void) close(s); 892 return (-1); 893 } 894 895 return (s); 896 } 897 898 /* 899 * dyndns_build_tkey_msg 900 * This routine is used to build the TKEY message to transmit GSS tokens 901 * during GSS security context establishment for secure DNS update. The 902 * TKEY message format uses the DNS query message format. The TKEY section 903 * is the answer section of the query message format. 904 * Microsoft uses a value of 86400 seconds (24 hours) for key expiration time. 905 * Parameters: 906 * buf : buffer to build and store TKEY message 907 * key_name: a unique key name, this same key name must be also be used in 908 * the TSIG message 909 * out_tok : TKEY message data (GSS tokens) 910 * Returns: 911 * id : message id of this TKEY message 912 * message size: the size of the TKEY message 913 * -1 : error 914 */ 915 static int 916 dyndns_build_tkey_msg(char *buf, char *key_name, uint16_t *id, 917 gss_buffer_desc *out_tok) 918 { 919 int queryReq, zoneCount, preqCount, updateCount, additionalCount; 920 int zoneType, zoneClass; 921 char *bufptr; 922 923 queryReq = REQ_QUERY; 924 /* query section of query request */ 925 zoneCount = 1; 926 /* answer section of query request */ 927 preqCount = 1; 928 updateCount = 0; 929 additionalCount = 0; 930 931 (void) memset(buf, 0, MAX_TCP_SIZE); 932 bufptr = buf; 933 *id = dyndns_get_msgid(); 934 935 /* add TCP length info that follows this field */ 936 bufptr = dyndns_put_nshort(bufptr, 937 26 + (strlen(key_name)+2)*2 + 35 + out_tok->length); 938 939 if (dyndns_build_header(&bufptr, BUFLEN_TCP(bufptr, buf), *id, queryReq, 940 zoneCount, preqCount, updateCount, additionalCount, 0) == -1) { 941 return (-1); 942 } 943 944 zoneType = ns_t_tkey; 945 zoneClass = ns_c_in; 946 if (dyndns_build_quest_zone(&bufptr, BUFLEN_TCP(bufptr, buf), key_name, 947 zoneType, zoneClass) == -1) { 948 return (-1); 949 } 950 951 if (dyndns_build_tkey(&bufptr, BUFLEN_TCP(bufptr, buf), key_name, 952 86400, out_tok->value, out_tok->length) == -1) { 953 return (-1); 954 } 955 956 return (bufptr - buf); 957 } 958 959 /* 960 * dyndns_establish_sec_ctx 961 * This routine is used to establish a security context with the DNS server 962 * by building TKEY messages and sending them to the DNS server. TKEY messages 963 * are also received from the DNS server for processing. The security context 964 * establishment is done with the GSS client on the system producing a token 965 * and sending the token within the TKEY message to the GSS server on the DNS 966 * server. The GSS server then processes the token and then send a TKEY reply 967 * message with a new token to be processed by the GSS client. The GSS client 968 * processes the new token and then generates a new token to be sent to the 969 * GSS server. This cycle is continued until the security establishment is 970 * done. TCP is used to send and receive TKEY messages. 971 * Parameters: 972 * cred_handle : handle to credential 973 * s : socket descriptor to DNS server 974 * key_name : TKEY key name 975 * dns_hostname: fully qualified DNS hostname 976 * oid : contains Kerberos 5 object identifier 977 * Returns: 978 * gss_context : handle to security context 979 */ 980 static int 981 dyndns_establish_sec_ctx(gss_ctx_id_t *gss_context, gss_cred_id_t cred_handle, 982 int s, char *key_name, char *dns_hostname, gss_OID oid) 983 { 984 uint16_t id, rid, rsz; 985 char buf[MAX_TCP_SIZE], buf2[MAX_TCP_SIZE]; 986 int ret; 987 char *service_name, *tmpptr; 988 int service_sz; 989 OM_uint32 min, maj, time_rec; 990 gss_buffer_desc service_buf, in_tok, out_tok; 991 gss_name_t target_name; 992 gss_buffer_desc *inputptr; 993 int gss_flags; 994 OM_uint32 ret_flags; 995 int buf_sz; 996 997 service_sz = strlen(dns_hostname) + 5; 998 service_name = (char *)malloc(sizeof (char) * service_sz); 999 if (service_name == NULL) 1000 return (-1); 1001 1002 (void) snprintf(service_name, service_sz, "DNS@%s", dns_hostname); 1003 service_buf.value = service_name; 1004 service_buf.length = strlen(service_name)+1; 1005 if ((maj = gss_import_name(&min, &service_buf, 1006 GSS_C_NT_HOSTBASED_SERVICE, &target_name)) != GSS_S_COMPLETE) { 1007 display_stat(maj, min); 1008 (void) free(service_name); 1009 return (-1); 1010 } 1011 (void) free(service_name); 1012 1013 inputptr = GSS_C_NO_BUFFER; 1014 *gss_context = GSS_C_NO_CONTEXT; 1015 gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | GSS_C_REPLAY_FLAG | 1016 GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG; 1017 do { 1018 maj = gss_init_sec_context(&min, cred_handle, gss_context, 1019 target_name, oid, gss_flags, 0, NULL, inputptr, NULL, 1020 &out_tok, &ret_flags, &time_rec); 1021 1022 if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) { 1023 assert(gss_context); 1024 if (*gss_context != GSS_C_NO_CONTEXT) 1025 (void) gss_delete_sec_context(&min, 1026 gss_context, NULL); 1027 1028 display_stat(maj, min); 1029 (void) gss_release_name(&min, &target_name); 1030 return (-1); 1031 } 1032 1033 if ((maj == GSS_S_COMPLETE) && 1034 !(ret_flags & GSS_C_REPLAY_FLAG)) { 1035 syslog(LOG_ERR, "dyndns: No GSS_C_REPLAY_FLAG"); 1036 if (out_tok.length > 0) 1037 (void) gss_release_buffer(&min, &out_tok); 1038 (void) gss_release_name(&min, &target_name); 1039 return (-1); 1040 } 1041 1042 if ((maj == GSS_S_COMPLETE) && 1043 !(ret_flags & GSS_C_MUTUAL_FLAG)) { 1044 syslog(LOG_ERR, "dyndns: No GSS_C_MUTUAL_FLAG"); 1045 if (out_tok.length > 0) 1046 (void) gss_release_buffer(&min, &out_tok); 1047 (void) gss_release_name(&min, &target_name); 1048 return (-1); 1049 } 1050 1051 if (out_tok.length > 0) { 1052 if ((buf_sz = dyndns_build_tkey_msg(buf, key_name, 1053 &id, &out_tok)) <= 0) { 1054 (void) gss_release_buffer(&min, &out_tok); 1055 (void) gss_release_name(&min, &target_name); 1056 return (-1); 1057 } 1058 1059 (void) gss_release_buffer(&min, &out_tok); 1060 1061 if (send(s, buf, buf_sz, 0) == -1) { 1062 syslog(LOG_ERR, "dyndns: TKEY send error"); 1063 (void) gss_release_name(&min, &target_name); 1064 return (-1); 1065 } 1066 1067 bzero(buf2, MAX_TCP_SIZE); 1068 if (recv(s, buf2, MAX_TCP_SIZE, 0) == -1) { 1069 syslog(LOG_ERR, "dyndns: TKEY recv error"); 1070 (void) gss_release_name(&min, &target_name); 1071 return (-1); 1072 } 1073 1074 ret = buf2[5] & 0xf; /* error field in TCP */ 1075 if (ret != NOERROR) { 1076 dyndns_syslog(LOG_ERR, ret, "TKEY reply"); 1077 (void) gss_release_name(&min, &target_name); 1078 return (-1); 1079 } 1080 1081 tmpptr = &buf2[2]; 1082 (void) dyndns_get_nshort(tmpptr, &rid); 1083 if (id != rid) { 1084 (void) gss_release_name(&min, &target_name); 1085 return (-1); 1086 } 1087 1088 tmpptr = &buf2[59+(strlen(key_name)+2)*2]; 1089 (void) dyndns_get_nshort(tmpptr, &rsz); 1090 in_tok.length = rsz; 1091 1092 /* bsd38 -> 2*7=14 */ 1093 in_tok.value = &buf2[61+(strlen(key_name)+2)*2]; 1094 inputptr = &in_tok; 1095 } 1096 1097 } while (maj != GSS_S_COMPLETE); 1098 1099 (void) gss_release_name(&min, &target_name); 1100 1101 return (0); 1102 } 1103 1104 /* 1105 * dyndns_get_sec_context 1106 * Get security context for secure dynamic DNS update. This routine opens 1107 * a TCP socket to the DNS server and establishes a security context with 1108 * the DNS server using host principal to perform secure dynamic DNS update. 1109 * Parameters: 1110 * hostname: fully qualified hostname 1111 * dns_ip : ip address of hostname in network byte order 1112 * Returns: 1113 * gss_handle: gss credential handle 1114 * gss_context: gss security context 1115 * -1: error 1116 * 0: success 1117 */ 1118 static gss_ctx_id_t 1119 dyndns_get_sec_context(const char *hostname, int dns_ip) 1120 { 1121 int s; 1122 gss_cred_id_t cred_handle; 1123 gss_ctx_id_t gss_context; 1124 gss_OID oid; 1125 struct hostent *hentry; 1126 char *key_name, dns_hostname[MAXHOSTNAMELEN]; 1127 1128 cred_handle = GSS_C_NO_CREDENTIAL; 1129 oid = GSS_C_NO_OID; 1130 key_name = (char *)hostname; 1131 1132 hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET); 1133 if (hentry == NULL) { 1134 syslog(LOG_ERR, "dyndns gethostbyaddr failed"); 1135 return (NULL); 1136 } 1137 (void) strcpy(dns_hostname, hentry->h_name); 1138 1139 if ((s = dyndns_open_init_socket(SOCK_STREAM, dns_ip, 53)) < 0) { 1140 return (NULL); 1141 } 1142 1143 if (dyndns_establish_sec_ctx(&gss_context, cred_handle, s, key_name, 1144 dns_hostname, oid)) 1145 gss_context = NULL; 1146 1147 (void) close(s); 1148 return (gss_context); 1149 } 1150 1151 /* 1152 * dyndns_build_add_remove_msg 1153 * This routine builds the update request message for adding and removing DNS 1154 * entries which is used for non-secure and secure DNS update. 1155 * This routine builds an UDP message. 1156 * Parameters: 1157 * buf : buffer to build message 1158 * update_zone: the type of zone to update, use UPDATE_FORW for forward 1159 * lookup zone, use UPDATE_REV for reverse lookup zone 1160 * hostname : fully qualified hostname to update DNS with 1161 * ip_addr : IP address of hostname 1162 * life_time : cached time of this entry by others and not within DNS 1163 * database 1164 * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1165 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1166 * entries of the same resource name. Only valid for UPDATE_DEL. 1167 * addit_cnt : Indicate how many record is in the additional section of 1168 * the DNS message. A value of zero is always used with 1169 * non-secure update message. For secure update message, 1170 * the value will be one because the signed TSIG message 1171 * is added as the additional record of the DNS update message. 1172 * id : DNS message ID. If a positive value then this ID value is 1173 * used, otherwise the next incremented value is used 1174 * level : This is the domain level which we send the request to, level 1175 * zero is the default level, it can go upto 2 in reverse zone 1176 * and virtually to any level in forward zone. 1177 * Returns: 1178 * buf : buffer containing update message 1179 * id : DNS message ID 1180 * int : size of update message 1181 * -1 : error 1182 * 1183 * This function is changed to handle dynamic DNS update retires to higher 1184 * authoritative domains. 1185 */ 1186 static int 1187 dyndns_build_add_remove_msg(char *buf, int update_zone, const char *hostname, 1188 const char *ip_addr, int life_time, int update_type, int del_type, 1189 int addit_cnt, uint16_t *id, int level) 1190 { 1191 int a, b, c, d; 1192 char *bufptr; 1193 int queryReq, zoneCount, preqCount, updateCount, additionalCount; 1194 char *zone, *resource, *data, zone_buf[100], resrc_buf[100]; 1195 int zoneType, zoneClass, type, class, ttl; 1196 char *p; 1197 1198 queryReq = REQ_UPDATE; 1199 zoneCount = 1; 1200 preqCount = 0; 1201 updateCount = 1; 1202 additionalCount = addit_cnt; 1203 1204 (void) memset(buf, 0, NS_PACKETSZ); 1205 bufptr = buf; 1206 1207 if (*id == 0) 1208 *id = dyndns_get_msgid(); 1209 1210 if (dyndns_build_header(&bufptr, BUFLEN_UDP(bufptr, buf), *id, queryReq, 1211 zoneCount, preqCount, updateCount, additionalCount, 0) == -1) { 1212 return (-1); 1213 } 1214 1215 zoneType = ns_t_soa; 1216 zoneClass = ns_c_in; 1217 1218 if (update_zone == UPDATE_FORW) { 1219 p = (char *)hostname; 1220 1221 /* Try higher domains according to the level requested */ 1222 do { 1223 /* domain */ 1224 if ((zone = (char *)strchr(p, '.')) == NULL) 1225 return (-1); 1226 zone += 1; 1227 p = zone; 1228 } while (--level >= 0); 1229 resource = (char *)hostname; 1230 data = (char *)ip_addr; 1231 } else { 1232 (void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d); 1233 (void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", c, b, a); 1234 zone = p = zone_buf; 1235 1236 /* Try higher domains according to the level requested */ 1237 while (--level >= 0) { 1238 /* domain */ 1239 if ((zone = (char *)strchr(p, '.')) == NULL) { 1240 return (-1); 1241 } 1242 zone += 1; 1243 p = zone; 1244 } 1245 1246 (void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa", 1247 d, c, b, a); 1248 resource = resrc_buf; /* ip info */ 1249 data = (char *)hostname; 1250 } 1251 1252 if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), zone, 1253 zoneType, zoneClass) == -1) { 1254 return (-1); 1255 } 1256 1257 if (update_zone == UPDATE_FORW) 1258 type = ns_t_a; 1259 else 1260 type = ns_t_ptr; 1261 1262 if (update_type == UPDATE_ADD) { 1263 class = ns_c_in; 1264 ttl = life_time; 1265 } else { 1266 if (del_type == DEL_ONE) 1267 class = ns_c_none; /* remove one */ 1268 else 1269 class = ns_c_any; /* remove all */ 1270 ttl = 0; 1271 } 1272 if (dyndns_build_update(&bufptr, BUFLEN_UDP(bufptr, buf), 1273 resource, type, class, ttl, data, update_zone, 1274 update_type, del_type) == -1) { 1275 return (-1); 1276 } 1277 1278 return (bufptr - buf); 1279 } 1280 1281 /* 1282 * dyndns_build_unsigned_tsig_msg 1283 * This routine is used to build the unsigned TSIG message for signing. The 1284 * unsigned TSIG message contains the update request message with certain TSIG 1285 * fields included. An error time of 300 seconds is used for fudge time. This 1286 * is the number used by Microsoft clients. 1287 * This routine builds a UDP message. 1288 * Parameters: 1289 * buf : buffer to build message 1290 * update_zone: the type of zone to update, use UPDATE_FORW for forward 1291 * lookup zone, use UPDATE_REV for reverse lookup zone 1292 * hostname : fully qualified hostname to update DNS with 1293 * ip_addr : IP address of hostname 1294 * life_time : cached time of this entry by others and not within DNS 1295 * database 1296 * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1297 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1298 * entries of the same resource name. Only valid for UPDATE_DEL. 1299 * key_name : same key name used in TKEY message 1300 * id : DNS message ID. If a positive value then this ID value is 1301 * used, otherwise the next incremented value is used 1302 * level : This is the domain level which we send the request to, level 1303 * zero is the default level, it can go upto 2 in reverse zone 1304 * and virtually to any level in forward zone. 1305 * Returns: 1306 * buf : buffer containing update message 1307 * id : DNS message ID 1308 * int : size of update message 1309 * -1 : error 1310 */ 1311 static int 1312 dyndns_build_unsigned_tsig_msg(char *buf, int update_zone, const char *hostname, 1313 const char *ip_addr, int life_time, int update_type, int del_type, 1314 char *key_name, uint16_t *id, int level) 1315 { 1316 char *bufptr; 1317 int buf_sz; 1318 1319 if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1320 ip_addr, life_time, update_type, del_type, 0, id, level)) <= 0) { 1321 return (-1); 1322 } 1323 1324 bufptr = buf + buf_sz; 1325 1326 if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf), 0, 1327 key_name, 300, NULL, 0, TSIG_UNSIGNED) == -1) { 1328 return (-1); 1329 } 1330 1331 return (bufptr - buf); 1332 } 1333 1334 /* 1335 * dyndns_build_signed_tsig_msg 1336 * This routine build the signed TSIG message which contains the update 1337 * request message encrypted. An error time of 300 seconds is used for fudge 1338 * time. This is the number used by Microsoft clients. 1339 * This routine builds a UDP message. 1340 * Parameters: 1341 * buf : buffer to build message 1342 * update_zone: the type of zone to update, use UPDATE_FORW for forward 1343 * lookup zone, use UPDATE_REV for reverse lookup zone 1344 * hostname : fully qualified hostname to update DNS with 1345 * ip_addr : IP address of hostname 1346 * life_time : cached time of this entry by others and not within DNS 1347 * database 1348 * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1349 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1350 * entries of the same resource name. Only valid for UPDATE_DEL. 1351 * key_name : same key name used in TKEY message 1352 * id : DNS message ID. If a positive value then this ID value is 1353 * used, otherwise the next incremented value is used 1354 * in_mic : the update request message encrypted 1355 * level : This is the domain level which we send the request to, level 1356 * zero is the default level, it can go upto 2 in reverse zone 1357 * and virtually to any level in forward zone. 1358 * 1359 * Returns: 1360 * buf : buffer containing update message 1361 * id : DNS message ID 1362 * int : size of update message 1363 * -1 : error 1364 */ 1365 static int 1366 dyndns_build_signed_tsig_msg(char *buf, int update_zone, const char *hostname, 1367 const char *ip_addr, int life_time, int update_type, int del_type, 1368 char *key_name, uint16_t *id, gss_buffer_desc *in_mic, int level) 1369 { 1370 char *bufptr; 1371 int buf_sz; 1372 1373 if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1374 ip_addr, life_time, update_type, del_type, 1, id, level)) <= 0) { 1375 return (-1); 1376 } 1377 1378 bufptr = buf + buf_sz; 1379 1380 if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf), 1381 *id, key_name, 300, in_mic->value, 1382 in_mic->length, TSIG_SIGNED) == -1) { 1383 return (-1); 1384 } 1385 1386 return (bufptr - buf); 1387 } 1388 1389 /* 1390 * dyndns_udp_send_recv 1391 * This routine sends and receives UDP DNS request and reply messages. 1392 * 1393 * Pre-condition: Caller must call dyndns_open_init_socket() before calling 1394 * this function. 1395 * 1396 * Parameters: 1397 * s : socket descriptor 1398 * buf : buffer containing data to send 1399 * buf_sz : size of data to send 1400 * Returns: 1401 * -1 : error 1402 * rec_buf: reply dat 1403 * 0 : success 1404 */ 1405 static int 1406 dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf) 1407 { 1408 int i, retval, addr_len; 1409 struct timeval tv, timeout; 1410 fd_set rfds; 1411 struct sockaddr_in from_addr; 1412 1413 timeout.tv_usec = 0; 1414 timeout.tv_sec = DYNDNS_QUERY_TIMEOUT; 1415 1416 for (i = 0; i <= DYNDNS_MAX_QUERY_RETRIES; i++) { 1417 if (send(s, buf, buf_sz, 0) == -1) { 1418 syslog(LOG_ERR, "dyndns: UDP send error (%s)", 1419 strerror(errno)); 1420 return (-1); 1421 } 1422 1423 FD_ZERO(&rfds); 1424 FD_SET(s, &rfds); 1425 1426 tv = timeout; 1427 1428 retval = select(s+1, &rfds, NULL, NULL, &tv); 1429 1430 if (retval == -1) { 1431 return (-1); 1432 } else if (retval > 0) { 1433 bzero(rec_buf, NS_PACKETSZ); 1434 /* required by recvfrom */ 1435 addr_len = sizeof (struct sockaddr_in); 1436 if (recvfrom(s, rec_buf, NS_PACKETSZ, 0, 1437 (struct sockaddr *)&from_addr, &addr_len) == -1) { 1438 syslog(LOG_ERR, "dyndns: UDP recv error"); 1439 return (-1); 1440 } 1441 break; 1442 } 1443 } 1444 1445 /* did not receive anything */ 1446 if (i == (DYNDNS_MAX_QUERY_RETRIES + 1)) { 1447 syslog(LOG_ERR, "dyndns: max retries for UDP recv reached"); 1448 return (-1); 1449 } 1450 1451 return (0); 1452 } 1453 1454 /* 1455 * dyndns_sec_add_remove_entry 1456 * Perform secure dynamic DNS update after getting security context. 1457 * This routine opens a UDP socket to the DNS sever, gets the security context, 1458 * builds the unsigned TSIG message and signed TSIG message. The signed TSIG 1459 * message containing the encrypted update request message is sent to the DNS 1460 * server. The response is received and check for error. If there is no 1461 * error then credential handle and security context are released and the local 1462 * NSS cached is purged. 1463 * Parameters: 1464 * update_zone : UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1465 * hostname : fully qualified hostname 1466 * ip_addr : ip address of hostname in string format 1467 * life_time : cached time of this entry by others and not within DNS 1468 * database 1469 * max_retries : maximum retries for sending DNS update request 1470 * recv_timeout: receive timeout 1471 * update_type : UPDATE_ADD for adding entry, UPDATE_DEL for removing entry 1472 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1473 * entries of the same resource name. Only valid for UPDATE_DEL 1474 * dns_str : DNS IP address in string format 1475 * Returns: 1476 * -1: error 1477 * 0: success 1478 * 1479 * This function is enhanced to handle the case of NOTAUTH error when DNS server 1480 * is not authoritative for specified zone. In this case we need to resend the 1481 * same request to the higher authoritative domains. 1482 * This is true for both secure and unsecure dynamic DNS updates. 1483 */ 1484 static int 1485 dyndns_sec_add_remove_entry(int update_zone, const char *hostname, 1486 const char *ip_addr, int life_time, int update_type, int del_type, 1487 char *dns_str) 1488 { 1489 int s2; 1490 uint16_t id, rid; 1491 char buf[NS_PACKETSZ], buf2[NS_PACKETSZ]; 1492 int ret; 1493 OM_uint32 min, maj; 1494 gss_buffer_desc in_mic, out_mic; 1495 gss_ctx_id_t gss_context; 1496 int dns_ip; 1497 char *key_name; 1498 int buf_sz; 1499 int level = 0; 1500 1501 assert(dns_str); 1502 assert(*dns_str); 1503 1504 dns_ip = inet_addr(dns_str); 1505 1506 sec_retry_higher: 1507 1508 if ((gss_context = dyndns_get_sec_context(hostname, 1509 dns_ip)) == NULL) { 1510 return (-1); 1511 } 1512 1513 key_name = (char *)hostname; 1514 1515 if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) { 1516 if (gss_context != GSS_C_NO_CONTEXT) 1517 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1518 return (-1); 1519 } 1520 1521 id = 0; 1522 if ((buf_sz = dyndns_build_unsigned_tsig_msg(buf, update_zone, hostname, 1523 ip_addr, life_time, update_type, del_type, 1524 key_name, &id, level)) <= 0) { 1525 (void) close(s2); 1526 if (gss_context != GSS_C_NO_CONTEXT) 1527 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1528 return (-1); 1529 } 1530 1531 in_mic.length = buf_sz; 1532 in_mic.value = buf; 1533 1534 /* sign update message */ 1535 if ((maj = gss_get_mic(&min, gss_context, 0, &in_mic, &out_mic)) != 1536 GSS_S_COMPLETE) { 1537 display_stat(maj, min); 1538 (void) close(s2); 1539 if (gss_context != GSS_C_NO_CONTEXT) 1540 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1541 return (-1); 1542 } 1543 1544 if ((buf_sz = dyndns_build_signed_tsig_msg(buf, update_zone, hostname, 1545 ip_addr, life_time, update_type, del_type, key_name, &id, 1546 &out_mic, level)) <= 0) { 1547 (void) close(s2); 1548 (void) gss_release_buffer(&min, &out_mic); 1549 if (gss_context != GSS_C_NO_CONTEXT) 1550 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1551 return (-1); 1552 } 1553 1554 (void) gss_release_buffer(&min, &out_mic); 1555 1556 if (dyndns_udp_send_recv(s2, buf, buf_sz, buf2)) { 1557 (void) close(s2); 1558 if (gss_context != GSS_C_NO_CONTEXT) 1559 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1560 return (-1); 1561 } 1562 1563 (void) close(s2); 1564 1565 if (gss_context != GSS_C_NO_CONTEXT) 1566 (void) gss_delete_sec_context(&min, &gss_context, NULL); 1567 1568 ret = buf2[3] & 0xf; /* error field in UDP */ 1569 1570 /* 1571 * If it is a NOTAUTH error we should retry with higher domains 1572 * until we get a successful reply or the maximum retries is met. 1573 */ 1574 if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES) 1575 goto sec_retry_higher; 1576 1577 /* check here for update request is successful */ 1578 if (ret != NOERROR) { 1579 dyndns_syslog(LOG_ERR, ret, "TSIG reply"); 1580 return (-1); 1581 } 1582 1583 (void) dyndns_get_nshort(buf2, &rid); 1584 if (id != rid) 1585 return (-1); 1586 1587 return (0); 1588 } 1589 1590 /* 1591 * dyndns_seach_entry 1592 * Query DNS server for entry. This routine can indicate if an entry exist 1593 * or not during forward or reverse lookup. Also can indicate if the data 1594 * of the entry matched. For example, for forward lookup, the entry is 1595 * searched using the hostname and the data is the IP address. For reverse 1596 * lookup, the entry is searched using the IP address and the data is the 1597 * hostname. 1598 * Parameters: 1599 * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1600 * hostname : fully qualified hostname 1601 * ip_addr : ip address of hostname in string format 1602 * update_type: UPDATE_ADD for adding entry, UPDATE_DEL for removing entry 1603 * Returns: 1604 * time_out: no use 1605 * is_match: is 1 for found matching entry, otherwise 0 1606 * 1 : an entry exist but not necessarily match 1607 * 0 : an entry does not exist 1608 */ 1609 /*ARGSUSED*/ 1610 static int 1611 dyndns_search_entry(int update_zone, const char *hostname, const char *ip_addr, 1612 int update_type, struct timeval *time_out, int *is_match) 1613 { 1614 struct hostent *hentry; 1615 struct in_addr in; 1616 in_addr_t ip; 1617 int i; 1618 1619 *is_match = 0; 1620 if (update_zone == UPDATE_FORW) { 1621 hentry = gethostbyname(hostname); 1622 if (hentry) { 1623 ip = inet_addr(ip_addr); 1624 for (i = 0; hentry->h_addr_list[i]; i++) { 1625 (void) memcpy(&in.s_addr, 1626 hentry->h_addr_list[i], sizeof (in.s_addr)); 1627 if (ip == in.s_addr) { 1628 *is_match = 1; 1629 break; 1630 } 1631 } 1632 return (1); 1633 } 1634 } else { 1635 int dns_ip = inet_addr(ip_addr); 1636 hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET); 1637 if (hentry) { 1638 if (strncasecmp(hentry->h_name, hostname, 1639 strlen(hostname)) == 0) { 1640 *is_match = 1; 1641 } 1642 return (1); 1643 } 1644 } 1645 1646 /* entry does not exist */ 1647 return (0); 1648 } 1649 1650 /* 1651 * dyndns_add_remove_entry 1652 * Perform non-secure dynamic DNS update. If it fails and host principal 1653 * keys can be found in the local keytab file, secure update will be performed. 1654 * 1655 * This routine opens a UDP socket to the DNS sever, build the update request 1656 * message, and sends the message to the DNS server. The response is received 1657 * and check for error. If there is no error then the local NSS cached is 1658 * purged. DNS may be used to check to see if an entry already exist before 1659 * adding or to see if an entry does exist before removing it. Adding 1660 * duplicate entries or removing non-existing entries does not cause any 1661 * problems. DNS is not check when doing a delete all. 1662 * Parameters: 1663 * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1664 * hostname : fully qualified hostname 1665 * ip_addr : ip address of hostname in string format 1666 * life_time : cached time of this entry by others and not within DNS 1667 * database 1668 * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1669 * do_check : DNS_CHECK to check first in DNS, DNS_NOCHECK for no DNS 1670 * checking before update 1671 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1672 * entries of the same resource name. Only valid for UPDATE_DEL. 1673 * dns_str : DNS IP address in string format 1674 * Returns: 1675 * -1: error 1676 * 0: success 1677 * 1678 * This function is enhanced to handle the case of NOTAUTH error when DNS server 1679 * is not authoritative for specified zone. In this case we need to resend the 1680 * same request to the higher authoritative domains. 1681 * This is true for both secure and unsecure dynamic DNS updates. 1682 */ 1683 static int 1684 dyndns_add_remove_entry(int update_zone, const char *hostname, 1685 const char *ip_addr, int life_time, int update_type, 1686 int do_check, int del_type, char *dns_str) 1687 { 1688 int s; 1689 uint16_t id, rid; 1690 char buf[NS_PACKETSZ], buf2[NS_PACKETSZ]; 1691 int ret, dns_ip; 1692 int is_exist, is_match; 1693 struct timeval timeout; 1694 int buf_sz; 1695 int level = 0; 1696 1697 assert(dns_str); 1698 assert(*dns_str); 1699 1700 dns_ip = inet_addr(dns_str); 1701 1702 if (do_check == DNS_CHECK && del_type != DEL_ALL) { 1703 is_exist = dyndns_search_entry(update_zone, hostname, ip_addr, 1704 update_type, &timeout, &is_match); 1705 1706 if (update_type == UPDATE_ADD && is_exist && is_match) { 1707 return (0); 1708 } else if (update_type == UPDATE_DEL && !is_exist) { 1709 return (0); 1710 } 1711 } 1712 1713 retry_higher: 1714 if ((s = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) { 1715 return (-1); 1716 } 1717 1718 id = 0; 1719 if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1720 ip_addr, life_time, update_type, del_type, 0, &id, level)) <= 0) { 1721 (void) close(s); 1722 return (-1); 1723 } 1724 1725 if (dyndns_udp_send_recv(s, buf, buf_sz, buf2)) { 1726 (void) close(s); 1727 return (-1); 1728 } 1729 1730 (void) close(s); 1731 1732 ret = buf2[3] & 0xf; /* error field in UDP */ 1733 1734 /* 1735 * If it is a NOTAUTH error we should retry with higher domains 1736 * until we get a successful reply 1737 */ 1738 if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES) 1739 goto retry_higher; 1740 1741 /* check here for update request is successful */ 1742 if (ret == NOERROR) { 1743 (void) dyndns_get_nshort(buf2, &rid); 1744 if (id != rid) 1745 return (-1); 1746 return (0); 1747 } 1748 1749 if (ret == NOTIMP) { 1750 dyndns_syslog(LOG_NOTICE, NOTIMP, "dynamic updates"); 1751 return (-1); 1752 } else if (ret == NOTAUTH) { 1753 dyndns_syslog(LOG_NOTICE, NOTAUTH, "DNS"); 1754 return (-1); 1755 } 1756 1757 if (smb_krb5_find_keytab_entries(hostname, SMBNS_KRB5_KEYTAB)) 1758 ret = dyndns_sec_add_remove_entry(update_zone, hostname, 1759 ip_addr, life_time, update_type, del_type, dns_str); 1760 1761 return (ret); 1762 } 1763 1764 /* 1765 * dyndns_add_entry 1766 * Main routine to add an entry into DNS. The attempt will be made on the 1767 * the servers returned by smb_get_nameserver(). Upon a successful 1768 * attempt on any one of the server, the function will exit with 0. 1769 * Otherwise, -1 is retuned to indicate the update attempt on all the 1770 * nameservers has failed. 1771 * 1772 * Parameters: 1773 * update_zone: the type of zone to update, use UPDATE_FORW for forward 1774 * lookup zone, use UPDATE_REV for reverse lookup zone 1775 * hostname : fully qualified hostname 1776 * ip_addr : ip address of hostname in string format 1777 * life_time : cached time of this entry by others and not within DNS 1778 * database 1779 * Returns: 1780 * -1: error 1781 * 0: success 1782 */ 1783 static int 1784 dyndns_add_entry(int update_zone, const char *hostname, const char *ip_addr, 1785 int life_time) 1786 { 1787 char *dns_str; 1788 char *which_zone; 1789 struct in_addr ns_list[MAXNS]; 1790 int i, cnt; 1791 int addr, rc = 0; 1792 1793 if (hostname == NULL || ip_addr == NULL) 1794 return (-1); 1795 1796 addr = (int)inet_addr(ip_addr); 1797 if ((addr == -1) || (addr == 0)) 1798 return (-1); 1799 1800 cnt = smb_get_nameservers(ns_list, MAXNS); 1801 1802 for (i = 0; i < cnt; i++) { 1803 dns_str = inet_ntoa(ns_list[i]); 1804 if ((dns_str == NULL) || 1805 (strcmp(dns_str, "0.0.0.0") == 0)) { 1806 continue; 1807 } 1808 1809 which_zone = (update_zone == UPDATE_FORW) ? 1810 "forward" : "reverse"; 1811 1812 syslog(LOG_DEBUG, "dyndns %s lookup zone update %s (%s)", 1813 which_zone, hostname, ip_addr); 1814 1815 if (dyndns_add_remove_entry(update_zone, hostname, 1816 ip_addr, life_time, 1817 UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_str) != -1) { 1818 rc = 1; 1819 break; 1820 } 1821 } 1822 1823 return (rc ? 0 : -1); 1824 } 1825 1826 /* 1827 * dyndns_remove_entry 1828 * Main routine to remove an entry or all entries of the same resource name 1829 * from DNS. The update attempt will be made on the primary DNS server. If 1830 * there is a failure then another attempt will be made on the secondary DNS 1831 * server. 1832 * Parameters: 1833 * update_zone: the type of zone to update, use UPDATE_FORW for forward 1834 * lookup zone, use UPDATE_REV for reverse lookup zone 1835 * hostname : fully qualified hostname 1836 * ip_addr : ip address of hostname in string format 1837 * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1838 * entries of the same resource name. Only valid for UPDATE_DEL 1839 * Returns: 1840 * -1: error 1841 * 0: success 1842 */ 1843 static int 1844 dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr, 1845 int del_type) 1846 { 1847 char *dns_str; 1848 char *which_zone; 1849 struct in_addr ns_list[MAXNS]; 1850 int i, cnt, scnt; 1851 int addr; 1852 1853 if ((hostname == NULL || ip_addr == NULL)) { 1854 return (-1); 1855 } 1856 1857 addr = (int)inet_addr(ip_addr); 1858 if ((addr == -1) || (addr == 0)) { 1859 return (-1); 1860 } 1861 1862 cnt = smb_get_nameservers(ns_list, MAXNS); 1863 scnt = 0; 1864 1865 for (i = 0; i < cnt; i++) { 1866 dns_str = inet_ntoa(ns_list[i]); 1867 if ((dns_str == NULL) || 1868 (strcmp(dns_str, "0.0.0.0") == 0)) { 1869 continue; 1870 } 1871 1872 which_zone = (update_zone == UPDATE_FORW) ? 1873 "forward" : "reverse"; 1874 1875 if (del_type == DEL_ONE) { 1876 syslog(LOG_DEBUG, 1877 "dyndns %s lookup zone remove %s (%s)", 1878 which_zone, hostname, ip_addr); 1879 } else { 1880 syslog(LOG_DEBUG, 1881 "dyndns %s lookup zone remove all %s", 1882 which_zone, hostname); 1883 } 1884 1885 if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, 0, 1886 UPDATE_DEL, DNS_NOCHECK, del_type, dns_str) != -1) { 1887 scnt++; 1888 break; 1889 } 1890 } 1891 if (scnt) 1892 return (0); 1893 return (-1); 1894 } 1895 1896 /* 1897 * dyndns_update_core 1898 * Perform dynamic update on both forward and reverse lookup zone using 1899 * the specified hostname and IP addresses. Before updating DNS, existing 1900 * host entries with the same hostname in the forward lookup zone are removed 1901 * and existing pointer entries with the same IP addresses in the reverse 1902 * lookup zone are removed. After DNS update, host entries for current 1903 * hostname will show current IP addresses and pointer entries for current 1904 * IP addresses will show current hostname. 1905 * Parameters: 1906 * fqhn - fully-qualified hostname 1907 * 1908 * Returns: 1909 * -1: some dynamic DNS updates errors 1910 * 0: successful or DDNS disabled. 1911 */ 1912 static int 1913 dyndns_update_core(char *fqdn) 1914 { 1915 int forw_update_ok, error; 1916 char *my_ip; 1917 struct in_addr addr; 1918 smb_niciter_t ni; 1919 int rc; 1920 char fqhn[MAXHOSTNAMELEN]; 1921 1922 if (fqdn == NULL || *fqdn == '\0') 1923 return (0); 1924 1925 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 1926 return (0); 1927 1928 if (smb_gethostname(fqhn, MAXHOSTNAMELEN, 0) != 0) 1929 return (-1); 1930 1931 (void) snprintf(fqhn, MAXHOSTNAMELEN, "%s.%s", fqhn, fqdn); 1932 error = 0; 1933 forw_update_ok = 0; 1934 1935 /* 1936 * Dummy IP is okay since we are removing all using the hostname. 1937 */ 1938 if (dyndns_remove_entry(UPDATE_FORW, fqhn, "1.1.1.1", DEL_ALL) == 0) { 1939 forw_update_ok = 1; 1940 } else { 1941 error++; 1942 } 1943 1944 if (smb_nic_getfirst(&ni) != 0) 1945 return (-1); 1946 1947 do { 1948 if (ni.ni_nic.nic_sysflags & (IFF_STANDBY | IFF_PRIVATE)) 1949 continue; 1950 1951 addr.s_addr = ni.ni_nic.nic_ip; 1952 my_ip = (char *)strdup(inet_ntoa(addr)); 1953 if (my_ip == NULL) { 1954 error++; 1955 continue; 1956 } 1957 1958 if (forw_update_ok) { 1959 rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_ip, 1960 DDNS_TTL); 1961 1962 if (rc == -1) 1963 error++; 1964 } 1965 1966 rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_ip, DEL_ALL); 1967 if (rc == 0) { 1968 rc = dyndns_add_entry(UPDATE_REV, fqhn, my_ip, 1969 DDNS_TTL); 1970 } 1971 1972 if (rc == -1) 1973 error++; 1974 1975 (void) free(my_ip); 1976 } while (smb_nic_getnext(&ni) == 0); 1977 1978 return ((error == 0) ? 0 : -1); 1979 } 1980 1981 /* 1982 * dyndns_clear_rev_zone 1983 * Clear the rev zone records. Must be called to clear the OLD if list 1984 * of down records prior to updating the list with new information. 1985 * 1986 * Parameters: 1987 * fqhn - fully-qualified hostname 1988 * Returns: 1989 * -1: some dynamic DNS updates errors 1990 * 0: successful or DDNS disabled. 1991 */ 1992 static int 1993 dyndns_clear_rev_zone(char *fqdn) 1994 { 1995 int error; 1996 char *my_ip; 1997 struct in_addr addr; 1998 smb_niciter_t ni; 1999 int rc; 2000 char fqhn[MAXHOSTNAMELEN]; 2001 2002 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 2003 return (0); 2004 2005 if (smb_gethostname(fqhn, MAXHOSTNAMELEN, 0) != 0) 2006 return (-1); 2007 2008 (void) snprintf(fqhn, MAXHOSTNAMELEN, "%s.%s", fqhn, fqdn); 2009 error = 0; 2010 2011 if (smb_nic_getfirst(&ni) != 0) 2012 return (-1); 2013 2014 do { 2015 if (ni.ni_nic.nic_sysflags & (IFF_STANDBY | IFF_PRIVATE)) 2016 continue; 2017 2018 addr.s_addr = ni.ni_nic.nic_ip; 2019 my_ip = (char *)strdup(inet_ntoa(addr)); 2020 if (my_ip == NULL) { 2021 error++; 2022 continue; 2023 } 2024 2025 rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_ip, DEL_ALL); 2026 if (rc != 0) 2027 error++; 2028 2029 (void) free(my_ip); 2030 } while (smb_nic_getnext(&ni) == 0); 2031 2032 return ((error == 0) ? 0 : -1); 2033 } 2034