1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23da6c28aaSamw */ 24da6c28aaSamw 25da6c28aaSamw #include <assert.h> 26da6c28aaSamw #include <errno.h> 27da6c28aaSamw #include <stdio.h> 28da6c28aaSamw #include <stdlib.h> 29da6c28aaSamw #include <strings.h> 30da6c28aaSamw #include <sys/types.h> 31da6c28aaSamw #include <sys/socket.h> 32da6c28aaSamw #include <netinet/in.h> 33da6c28aaSamw #include <arpa/inet.h> 348d7e4166Sjose borrego #include <arpa/nameser.h> 358d7e4166Sjose borrego #include <net/if.h> 368d7e4166Sjose borrego #include <resolv.h> 37da6c28aaSamw #include <sys/time.h> 38da6c28aaSamw #include <unistd.h> 39da6c28aaSamw #include <string.h> 408d7e4166Sjose borrego #include <pthread.h> 41da6c28aaSamw #include <netdb.h> 42da6c28aaSamw #include <rpc/rpc.h> 43da6c28aaSamw #include <syslog.h> 44da6c28aaSamw #include <gssapi/gssapi.h> 45da6c28aaSamw #include <kerberosv5/krb5.h> 46da6c28aaSamw 47da6c28aaSamw #include <smbns_dyndns.h> 48faa1795aSjb150015 #include <smbns_krb.h> 49da6c28aaSamw 50c8ec8eeaSjose borrego /* 518d7e4166Sjose borrego * The following can be removed once head/arpa/nameser_compat.h 528d7e4166Sjose borrego * defines BADSIG, BADKEY and BADTIME. 53da6c28aaSamw */ 54da6c28aaSamw #ifndef BADSIG 55da6c28aaSamw #define BADSIG ns_r_badsig 56da6c28aaSamw #endif /* BADSIG */ 57da6c28aaSamw 58da6c28aaSamw #ifndef BADKEY 59da6c28aaSamw #define BADKEY ns_r_badkey 60da6c28aaSamw #endif /* BADKEY */ 61da6c28aaSamw 62da6c28aaSamw #ifndef BADTIME 63da6c28aaSamw #define BADTIME ns_r_badtime 64da6c28aaSamw #endif /* BADTIME */ 65da6c28aaSamw 668d7e4166Sjose borrego /* internal use, in dyndns_add_entry */ 678d7e4166Sjose borrego #define DEL_NONE 2 688d7e4166Sjose borrego 698d7e4166Sjose borrego /* Maximum retires if not authoritative */ 708d7e4166Sjose borrego #define MAX_AUTH_RETRIES 3 718d7e4166Sjose borrego 728d7e4166Sjose borrego /* Number of times to retry a DNS query */ 738d7e4166Sjose borrego #define DYNDNS_MAX_QUERY_RETRIES 3 748d7e4166Sjose borrego 758d7e4166Sjose borrego /* Timeout value, in seconds, for DNS query responses */ 768d7e4166Sjose borrego #define DYNDNS_QUERY_TIMEOUT 2 778d7e4166Sjose borrego 788d7e4166Sjose borrego static uint16_t dns_msgid; 798d7e4166Sjose borrego mutex_t dns_msgid_mtx; 808d7e4166Sjose borrego 818d7e4166Sjose borrego #define DYNDNS_OP_CLEAR 1 828d7e4166Sjose borrego #define DYNDNS_OP_UPDATE 2 838d7e4166Sjose borrego 848d7e4166Sjose borrego #define DYNDNS_STATE_INIT 0 858d7e4166Sjose borrego #define DYNDNS_STATE_READY 1 868d7e4166Sjose borrego #define DYNDNS_STATE_PUBLISHING 2 878d7e4166Sjose borrego #define DYNDNS_STATE_STOPPING 3 888d7e4166Sjose borrego 898d7e4166Sjose borrego typedef struct dyndns_qentry { 908d7e4166Sjose borrego list_node_t dqe_lnd; 918d7e4166Sjose borrego int dqe_op; 929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* fully-qualified domain name is in lower case */ 938d7e4166Sjose borrego char dqe_fqdn[MAXHOSTNAMELEN]; 948d7e4166Sjose borrego } dyndns_qentry_t; 958d7e4166Sjose borrego 968d7e4166Sjose borrego typedef struct dyndns_queue { 978d7e4166Sjose borrego list_t ddq_list; 988d7e4166Sjose borrego mutex_t ddq_mtx; 998d7e4166Sjose borrego cond_t ddq_cv; 1008d7e4166Sjose borrego uint32_t ddq_state; 1018d7e4166Sjose borrego } dyndns_queue_t; 1028d7e4166Sjose borrego 1038d7e4166Sjose borrego static dyndns_queue_t dyndns_queue; 1048d7e4166Sjose borrego 1058d7e4166Sjose borrego static void dyndns_queue_request(int, const char *); 1068d7e4166Sjose borrego static void dyndns_queue_flush(list_t *); 1078d7e4166Sjose borrego static void dyndns_process(list_t *); 1088d7e4166Sjose borrego static int dyndns_update_core(char *); 1098d7e4166Sjose borrego static int dyndns_clear_rev_zone(char *); 1108d7e4166Sjose borrego static void dyndns_msgid_init(void); 1118d7e4166Sjose borrego static int dyndns_get_msgid(void); 1128d7e4166Sjose borrego static void dyndns_syslog(int, int, const char *); 1138d7e4166Sjose borrego 114*fd9ee8b5Sjoyce mcintosh void 1158d7e4166Sjose borrego dyndns_start(void) 1168d7e4166Sjose borrego { 1178d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 118*fd9ee8b5Sjoyce mcintosh 1198d7e4166Sjose borrego if (dyndns_queue.ddq_state != DYNDNS_STATE_INIT) { 1208d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 121*fd9ee8b5Sjoyce mcintosh return; 1228d7e4166Sjose borrego } 1238d7e4166Sjose borrego 1248d7e4166Sjose borrego dyndns_msgid_init(); 1258d7e4166Sjose borrego 1268d7e4166Sjose borrego list_create(&dyndns_queue.ddq_list, sizeof (dyndns_qentry_t), 1278d7e4166Sjose borrego offsetof(dyndns_qentry_t, dqe_lnd)); 1288d7e4166Sjose borrego dyndns_queue.ddq_state = DYNDNS_STATE_READY; 1298d7e4166Sjose borrego 130*fd9ee8b5Sjoyce mcintosh (void) mutex_unlock(&dyndns_queue.ddq_mtx); 1318d7e4166Sjose borrego } 1328d7e4166Sjose borrego 1338d7e4166Sjose borrego void 1348d7e4166Sjose borrego dyndns_stop(void) 1358d7e4166Sjose borrego { 1368d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 1378d7e4166Sjose borrego 1388d7e4166Sjose borrego switch (dyndns_queue.ddq_state) { 1398d7e4166Sjose borrego case DYNDNS_STATE_READY: 1408d7e4166Sjose borrego case DYNDNS_STATE_PUBLISHING: 1418d7e4166Sjose borrego dyndns_queue.ddq_state = DYNDNS_STATE_STOPPING; 1428d7e4166Sjose borrego (void) cond_signal(&dyndns_queue.ddq_cv); 1438d7e4166Sjose borrego break; 1448d7e4166Sjose borrego default: 1458d7e4166Sjose borrego break; 1468d7e4166Sjose borrego } 1478d7e4166Sjose borrego 1488d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 1498d7e4166Sjose borrego } 1508d7e4166Sjose borrego 151da6c28aaSamw /* 1528d7e4166Sjose borrego * Clear all records in both zones. 1538d7e4166Sjose borrego */ 1548d7e4166Sjose borrego void 1558d7e4166Sjose borrego dyndns_clear_zones(void) 1568d7e4166Sjose borrego { 1578d7e4166Sjose borrego char fqdn[MAXHOSTNAMELEN]; 1588d7e4166Sjose borrego 1598d7e4166Sjose borrego if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) != 0) { 1608d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: failed to get domainname"); 1618d7e4166Sjose borrego return; 1628d7e4166Sjose borrego } 1638d7e4166Sjose borrego 1648d7e4166Sjose borrego dyndns_queue_request(DYNDNS_OP_CLEAR, fqdn); 1658d7e4166Sjose borrego } 1668d7e4166Sjose borrego 1678d7e4166Sjose borrego /* 1688d7e4166Sjose borrego * Update all records in both zones. 1698d7e4166Sjose borrego */ 1708d7e4166Sjose borrego void 1718d7e4166Sjose borrego dyndns_update_zones(void) 1728d7e4166Sjose borrego { 1738d7e4166Sjose borrego char fqdn[MAXHOSTNAMELEN]; 1748d7e4166Sjose borrego 1758d7e4166Sjose borrego if (smb_getfqdomainname(fqdn, MAXHOSTNAMELEN) != 0) { 1768d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: failed to get domainname"); 1778d7e4166Sjose borrego return; 1788d7e4166Sjose borrego } 1798d7e4166Sjose borrego 1808d7e4166Sjose borrego dyndns_queue_request(DYNDNS_OP_UPDATE, fqdn); 1818d7e4166Sjose borrego } 1828d7e4166Sjose borrego 1838d7e4166Sjose borrego /* 1848d7e4166Sjose borrego * Add a request to the queue. 185*fd9ee8b5Sjoyce mcintosh * 186*fd9ee8b5Sjoyce mcintosh * To comply with RFC 4120 section 6.2.1, entry->dqe_fqdn is converted 187*fd9ee8b5Sjoyce mcintosh * to lower case. 188da6c28aaSamw */ 1893db3f65cSamw static void 1908d7e4166Sjose borrego dyndns_queue_request(int op, const char *fqdn) 191da6c28aaSamw { 1928d7e4166Sjose borrego dyndns_qentry_t *entry; 193da6c28aaSamw 1948d7e4166Sjose borrego if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 1958d7e4166Sjose borrego return; 1968d7e4166Sjose borrego 197*fd9ee8b5Sjoyce mcintosh if ((entry = malloc(sizeof (dyndns_qentry_t))) == NULL) 198*fd9ee8b5Sjoyce mcintosh return; 199*fd9ee8b5Sjoyce mcintosh 200*fd9ee8b5Sjoyce mcintosh bzero(entry, sizeof (dyndns_qentry_t)); 201*fd9ee8b5Sjoyce mcintosh entry->dqe_op = op; 202*fd9ee8b5Sjoyce mcintosh (void) strlcpy(entry->dqe_fqdn, fqdn, MAXNAMELEN); 203*fd9ee8b5Sjoyce mcintosh (void) smb_strlwr(entry->dqe_fqdn); 204*fd9ee8b5Sjoyce mcintosh 2058d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 2068d7e4166Sjose borrego 2078d7e4166Sjose borrego switch (dyndns_queue.ddq_state) { 2088d7e4166Sjose borrego case DYNDNS_STATE_READY: 2098d7e4166Sjose borrego case DYNDNS_STATE_PUBLISHING: 2108d7e4166Sjose borrego list_insert_tail(&dyndns_queue.ddq_list, entry); 2118d7e4166Sjose borrego (void) cond_signal(&dyndns_queue.ddq_cv); 212*fd9ee8b5Sjoyce mcintosh break; 213*fd9ee8b5Sjoyce mcintosh default: 214*fd9ee8b5Sjoyce mcintosh free(entry); 215*fd9ee8b5Sjoyce mcintosh break; 216*fd9ee8b5Sjoyce mcintosh } 217*fd9ee8b5Sjoyce mcintosh 2188d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2198d7e4166Sjose borrego } 2208d7e4166Sjose borrego 2218d7e4166Sjose borrego /* 2228d7e4166Sjose borrego * Flush all remaining items from the specified list/queue. 2238d7e4166Sjose borrego */ 2248d7e4166Sjose borrego static void 2258d7e4166Sjose borrego dyndns_queue_flush(list_t *lst) 2268d7e4166Sjose borrego { 2278d7e4166Sjose borrego dyndns_qentry_t *entry; 2288d7e4166Sjose borrego 2298d7e4166Sjose borrego while ((entry = list_head(lst)) != NULL) { 2308d7e4166Sjose borrego list_remove(lst, entry); 2318d7e4166Sjose borrego free(entry); 2328d7e4166Sjose borrego } 2338d7e4166Sjose borrego } 2348d7e4166Sjose borrego 2358d7e4166Sjose borrego /* 2368d7e4166Sjose borrego * Dyndns update thread. While running, the thread waits on a condition 2378d7e4166Sjose borrego * variable until notified that an entry needs to be updated. 2388d7e4166Sjose borrego * 2398d7e4166Sjose borrego * If the outgoing queue is not empty, the thread wakes up every 60 seconds 2408d7e4166Sjose borrego * to retry. 2418d7e4166Sjose borrego */ 2428d7e4166Sjose borrego /*ARGSUSED*/ 243*fd9ee8b5Sjoyce mcintosh void * 2448d7e4166Sjose borrego dyndns_publisher(void *arg) 2458d7e4166Sjose borrego { 2468d7e4166Sjose borrego dyndns_qentry_t *entry; 2478d7e4166Sjose borrego list_t publist; 2488d7e4166Sjose borrego 2498d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 2508d7e4166Sjose borrego if (dyndns_queue.ddq_state != DYNDNS_STATE_READY) { 2518d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2528d7e4166Sjose borrego return (NULL); 2538d7e4166Sjose borrego } 2548d7e4166Sjose borrego dyndns_queue.ddq_state = DYNDNS_STATE_PUBLISHING; 2558d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2568d7e4166Sjose borrego 2578d7e4166Sjose borrego list_create(&publist, sizeof (dyndns_qentry_t), 2588d7e4166Sjose borrego offsetof(dyndns_qentry_t, dqe_lnd)); 2598d7e4166Sjose borrego 2608d7e4166Sjose borrego for (;;) { 2618d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 2628d7e4166Sjose borrego 2638d7e4166Sjose borrego while (list_is_empty(&dyndns_queue.ddq_list) && 2648d7e4166Sjose borrego (dyndns_queue.ddq_state == DYNDNS_STATE_PUBLISHING)) { 2658d7e4166Sjose borrego (void) cond_wait(&dyndns_queue.ddq_cv, 2668d7e4166Sjose borrego &dyndns_queue.ddq_mtx); 2678d7e4166Sjose borrego } 2688d7e4166Sjose borrego 2698d7e4166Sjose borrego if (dyndns_queue.ddq_state != DYNDNS_STATE_PUBLISHING) { 2708d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2718d7e4166Sjose borrego break; 2728d7e4166Sjose borrego } 2738d7e4166Sjose borrego 2748d7e4166Sjose borrego /* 2758d7e4166Sjose borrego * Transfer queued items to the local list so that 2768d7e4166Sjose borrego * the mutex can be released. 2778d7e4166Sjose borrego */ 2788d7e4166Sjose borrego while ((entry = list_head(&dyndns_queue.ddq_list)) != NULL) { 2798d7e4166Sjose borrego list_remove(&dyndns_queue.ddq_list, entry); 2808d7e4166Sjose borrego list_insert_tail(&publist, entry); 2818d7e4166Sjose borrego } 2828d7e4166Sjose borrego 2838d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2848d7e4166Sjose borrego 2858d7e4166Sjose borrego dyndns_process(&publist); 2868d7e4166Sjose borrego } 2878d7e4166Sjose borrego 2888d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 2898d7e4166Sjose borrego dyndns_queue_flush(&dyndns_queue.ddq_list); 2908d7e4166Sjose borrego list_destroy(&dyndns_queue.ddq_list); 2918d7e4166Sjose borrego dyndns_queue.ddq_state = DYNDNS_STATE_INIT; 2928d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 2938d7e4166Sjose borrego 2948d7e4166Sjose borrego dyndns_queue_flush(&publist); 2958d7e4166Sjose borrego list_destroy(&publist); 2968d7e4166Sjose borrego return (NULL); 2978d7e4166Sjose borrego } 2988d7e4166Sjose borrego 2998d7e4166Sjose borrego /* 3008d7e4166Sjose borrego * Remove items from the queue and process them. 3018d7e4166Sjose borrego */ 3028d7e4166Sjose borrego static void 3038d7e4166Sjose borrego dyndns_process(list_t *publist) 3048d7e4166Sjose borrego { 3058d7e4166Sjose borrego dyndns_qentry_t *entry; 3068d7e4166Sjose borrego 3078d7e4166Sjose borrego while ((entry = list_head(publist)) != NULL) { 3088d7e4166Sjose borrego (void) mutex_lock(&dyndns_queue.ddq_mtx); 3098d7e4166Sjose borrego if (dyndns_queue.ddq_state != DYNDNS_STATE_PUBLISHING) { 3108d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 3118d7e4166Sjose borrego dyndns_queue_flush(publist); 3128d7e4166Sjose borrego return; 3138d7e4166Sjose borrego } 3148d7e4166Sjose borrego (void) mutex_unlock(&dyndns_queue.ddq_mtx); 3158d7e4166Sjose borrego 3168d7e4166Sjose borrego list_remove(publist, entry); 3178d7e4166Sjose borrego 3188d7e4166Sjose borrego switch (entry->dqe_op) { 3198d7e4166Sjose borrego case DYNDNS_OP_CLEAR: 3208d7e4166Sjose borrego (void) dyndns_clear_rev_zone(entry->dqe_fqdn); 3218d7e4166Sjose borrego break; 3228d7e4166Sjose borrego case DYNDNS_OP_UPDATE: 3238d7e4166Sjose borrego (void) dyndns_update_core(entry->dqe_fqdn); 3248d7e4166Sjose borrego break; 3258d7e4166Sjose borrego default: 3268d7e4166Sjose borrego break; 3278d7e4166Sjose borrego } 3288d7e4166Sjose borrego 3298d7e4166Sjose borrego free(entry); 3308d7e4166Sjose borrego } 3318d7e4166Sjose borrego } 3328d7e4166Sjose borrego 3338d7e4166Sjose borrego /* 3348d7e4166Sjose borrego * Dynamic DNS update API for kclient. 3358d7e4166Sjose borrego * 3368d7e4166Sjose borrego * Returns 0 upon success. Otherwise, returns -1. 3378d7e4166Sjose borrego */ 3388d7e4166Sjose borrego int 3398d7e4166Sjose borrego dyndns_update(char *fqdn) 3408d7e4166Sjose borrego { 3418d7e4166Sjose borrego int rc; 3428d7e4166Sjose borrego 3439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_nic_init() != SMB_NIC_SUCCESS) 3448d7e4166Sjose borrego return (-1); 3458d7e4166Sjose borrego 3468d7e4166Sjose borrego dyndns_msgid_init(); 3479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_strlwr(fqdn); 3488d7e4166Sjose borrego rc = dyndns_update_core(fqdn); 3498d7e4166Sjose borrego smb_nic_fini(); 3508d7e4166Sjose borrego return (rc); 3518d7e4166Sjose borrego } 3528d7e4166Sjose borrego 3538d7e4166Sjose borrego /* 3548d7e4166Sjose borrego * Initializes the DNS message ID counter using the algorithm 3558d7e4166Sjose borrego * that resolver library uses to initialize the ID field of any res 3568d7e4166Sjose borrego * structure. 3578d7e4166Sjose borrego */ 3588d7e4166Sjose borrego static void 3598d7e4166Sjose borrego dyndns_msgid_init(void) 3608d7e4166Sjose borrego { 3618d7e4166Sjose borrego struct timeval now; 3628d7e4166Sjose borrego 3638d7e4166Sjose borrego (void) gettimeofday(&now, NULL); 3648d7e4166Sjose borrego (void) mutex_lock(&dns_msgid_mtx); 3658d7e4166Sjose borrego dns_msgid = (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); 3668d7e4166Sjose borrego (void) mutex_unlock(&dns_msgid_mtx); 3678d7e4166Sjose borrego } 3688d7e4166Sjose borrego 3698d7e4166Sjose borrego static int 3708d7e4166Sjose borrego dyndns_get_msgid(void) 3718d7e4166Sjose borrego { 3728d7e4166Sjose borrego uint16_t id; 3738d7e4166Sjose borrego 3748d7e4166Sjose borrego (void) mutex_lock(&dns_msgid_mtx); 3758d7e4166Sjose borrego id = ++dns_msgid; 3768d7e4166Sjose borrego (void) mutex_unlock(&dns_msgid_mtx); 3778d7e4166Sjose borrego return (id); 3788d7e4166Sjose borrego } 3798d7e4166Sjose borrego 3808d7e4166Sjose borrego /* 3818d7e4166Sjose borrego * Log a DNS error message 3828d7e4166Sjose borrego */ 3838d7e4166Sjose borrego static void 3848d7e4166Sjose borrego dyndns_syslog(int severity, int errnum, const char *text) 3858d7e4166Sjose borrego { 3868d7e4166Sjose borrego struct { 3878d7e4166Sjose borrego int errnum; 3888d7e4166Sjose borrego char *errmsg; 3898d7e4166Sjose borrego } errtab[] = { 3908d7e4166Sjose borrego { FORMERR, "message format error" }, 3918d7e4166Sjose borrego { SERVFAIL, "server internal error" }, 3928d7e4166Sjose borrego { NXDOMAIN, "entry should exist but does not exist" }, 3938d7e4166Sjose borrego { NOTIMP, "not supported" }, 3948d7e4166Sjose borrego { REFUSED, "operation refused" }, 3958d7e4166Sjose borrego { YXDOMAIN, "entry should not exist but does exist" }, 3968d7e4166Sjose borrego { YXRRSET, "RRSet should not exist but does exist" }, 3978d7e4166Sjose borrego { NXRRSET, "RRSet should exist but does not exist" }, 3988d7e4166Sjose borrego { NOTAUTH, "server is not authoritative for specified zone" }, 3998d7e4166Sjose borrego { NOTZONE, "name not within specified zone" }, 4008d7e4166Sjose borrego { BADSIG, "bad transaction signature (TSIG)" }, 4018d7e4166Sjose borrego { BADKEY, "bad transaction key (TKEY)" }, 4028d7e4166Sjose borrego { BADTIME, "time not synchronized" }, 4038d7e4166Sjose borrego }; 4048d7e4166Sjose borrego 4058d7e4166Sjose borrego char *errmsg = "unknown error"; 4068d7e4166Sjose borrego int i; 4078d7e4166Sjose borrego 4088d7e4166Sjose borrego if (errnum == NOERROR) 4098d7e4166Sjose borrego return; 4108d7e4166Sjose borrego 4118d7e4166Sjose borrego for (i = 0; i < (sizeof (errtab) / sizeof (errtab[0])); ++i) { 4128d7e4166Sjose borrego if (errtab[i].errnum == errnum) { 4138d7e4166Sjose borrego errmsg = errtab[i].errmsg; 4148d7e4166Sjose borrego break; 4158d7e4166Sjose borrego } 4168d7e4166Sjose borrego } 4178d7e4166Sjose borrego 4188d7e4166Sjose borrego syslog(severity, "dyndns: %s: %s: %d", text, errmsg, errnum); 419da6c28aaSamw } 420da6c28aaSamw 421da6c28aaSamw /* 422da6c28aaSamw * display_stat 423da6c28aaSamw * Display GSS error message from error code. This routine is used to display 424da6c28aaSamw * the mechanism independent and mechanism specific error messages for GSS 425da6c28aaSamw * routines. The major status error code is the mechanism independent error 426da6c28aaSamw * code and the minor status error code is the mechanism specific error code. 427da6c28aaSamw * Parameters: 428da6c28aaSamw * maj: GSS major status 429da6c28aaSamw * min: GSS minor status 430da6c28aaSamw * Returns: 431da6c28aaSamw * None 432da6c28aaSamw */ 433da6c28aaSamw static void 434da6c28aaSamw display_stat(OM_uint32 maj, OM_uint32 min) 435da6c28aaSamw { 436da6c28aaSamw gss_buffer_desc msg; 437da6c28aaSamw OM_uint32 msg_ctx = 0; 438da6c28aaSamw OM_uint32 min2; 439b89a8333Snatalie li - Sun Microsystems - Irvine United States 440da6c28aaSamw (void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, 441da6c28aaSamw &msg_ctx, &msg); 4428d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: GSS major status error: %s", 443da6c28aaSamw (char *)msg.value); 444b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) gss_release_buffer(&min2, &msg); 445b89a8333Snatalie li - Sun Microsystems - Irvine United States 446da6c28aaSamw (void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, 447da6c28aaSamw &msg_ctx, &msg); 4488d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: GSS minor status error: %s", 449da6c28aaSamw (char *)msg.value); 450b89a8333Snatalie li - Sun Microsystems - Irvine United States (void) gss_release_buffer(&min2, &msg); 451da6c28aaSamw } 452da6c28aaSamw 453da6c28aaSamw static char * 454da6c28aaSamw dyndns_put_nshort(char *buf, uint16_t val) 455da6c28aaSamw { 456da6c28aaSamw uint16_t nval; 457da6c28aaSamw 458da6c28aaSamw nval = htons(val); 459da6c28aaSamw (void) memcpy(buf, &nval, sizeof (uint16_t)); 460da6c28aaSamw buf += sizeof (uint16_t); 461da6c28aaSamw return (buf); 462da6c28aaSamw } 463da6c28aaSamw 4643db3f65cSamw static char * 465da6c28aaSamw dyndns_get_nshort(char *buf, uint16_t *val) 466da6c28aaSamw { 467da6c28aaSamw uint16_t nval; 468da6c28aaSamw 469da6c28aaSamw (void) memcpy(&nval, buf, sizeof (uint16_t)); 470da6c28aaSamw *val = ntohs(nval); 471da6c28aaSamw buf += sizeof (uint16_t); 472da6c28aaSamw return (buf); 473da6c28aaSamw } 474da6c28aaSamw 475da6c28aaSamw static char * 476da6c28aaSamw dyndns_put_nlong(char *buf, uint32_t val) 477da6c28aaSamw { 478da6c28aaSamw uint32_t lval; 479da6c28aaSamw 480da6c28aaSamw lval = htonl(val); 481da6c28aaSamw (void) memcpy(buf, &lval, sizeof (uint32_t)); 482da6c28aaSamw buf += sizeof (uint32_t); 483da6c28aaSamw return (buf); 484da6c28aaSamw } 485da6c28aaSamw 486da6c28aaSamw static char * 487da6c28aaSamw dyndns_put_byte(char *buf, char val) 488da6c28aaSamw { 489da6c28aaSamw *buf = val; 490da6c28aaSamw buf++; 491da6c28aaSamw return (buf); 492da6c28aaSamw } 493da6c28aaSamw 4947f667e74Sjose borrego 4957f667e74Sjose borrego 4967f667e74Sjose borrego 497da6c28aaSamw static char * 498da6c28aaSamw dyndns_put_int(char *buf, int val) 499da6c28aaSamw { 500da6c28aaSamw (void) memcpy(buf, &val, sizeof (int)); 501da6c28aaSamw buf += sizeof (int); 502da6c28aaSamw return (buf); 503da6c28aaSamw } 504da6c28aaSamw 5057f667e74Sjose borrego static char * 5067f667e74Sjose borrego dyndns_put_v6addr(char *buf, smb_inaddr_t *val) 5077f667e74Sjose borrego { 5087f667e74Sjose borrego 5097f667e74Sjose borrego val->a_family = AF_INET6; 5107f667e74Sjose borrego (void) memcpy(buf, &val->a_ipv6, IN6ADDRSZ); 5117f667e74Sjose borrego buf += IN6ADDRSZ; 5127f667e74Sjose borrego return (buf); 5137f667e74Sjose borrego } 514da6c28aaSamw /* 515da6c28aaSamw * dyndns_stuff_str 516da6c28aaSamw * Converts a domain string by removing periods and replacing with a byte value 517da6c28aaSamw * of how many characters following period. A byte value is placed in front 518da6c28aaSamw * to indicate how many characters before first period. A NULL character is 519da6c28aaSamw * placed at the end. i.e. host.procom.com -> 4host5procom3com0 520da6c28aaSamw * Buffer space checking is done by caller. 521da6c28aaSamw * Parameters: 522da6c28aaSamw * ptr : address of pointer to buffer to store converted string 523da6c28aaSamw * zone: domain name string 524da6c28aaSamw * Returns: 525da6c28aaSamw * ptr: address of pointer to next available buffer space 526da6c28aaSamw * -1 : error 527da6c28aaSamw * 0 : success 528da6c28aaSamw */ 529da6c28aaSamw static int 530da6c28aaSamw dyndns_stuff_str(char **ptr, char *zone) 531da6c28aaSamw { 532da6c28aaSamw int len; 533da6c28aaSamw char *lenPtr, *zonePtr; 534da6c28aaSamw 535da6c28aaSamw for (zonePtr = zone; *zonePtr; ) { 536da6c28aaSamw lenPtr = *ptr; 537da6c28aaSamw *ptr = *ptr + 1; 538da6c28aaSamw len = 0; 539da6c28aaSamw while (*zonePtr != '.' && *zonePtr != 0) { 540da6c28aaSamw *ptr = dyndns_put_byte(*ptr, *zonePtr); 541da6c28aaSamw zonePtr++; 542da6c28aaSamw len++; 543da6c28aaSamw } 544da6c28aaSamw *lenPtr = len; 545da6c28aaSamw if (*zonePtr == '.') 546da6c28aaSamw zonePtr++; 547da6c28aaSamw } 548da6c28aaSamw *ptr = dyndns_put_byte(*ptr, 0); 549da6c28aaSamw return (0); 550da6c28aaSamw } 551da6c28aaSamw 552da6c28aaSamw /* 553da6c28aaSamw * dyndns_build_header 554da6c28aaSamw * Build the header for DNS query and DNS update request message. 555da6c28aaSamw * Parameters: 556da6c28aaSamw * ptr : address of pointer to buffer to store header 557da6c28aaSamw * buf_len : buffer length 558da6c28aaSamw * msg_id : message id 559da6c28aaSamw * query_req : use REQ_QUERY for query message or REQ_UPDATE for 560da6c28aaSamw * update message 561da6c28aaSamw * quest_zone_cnt : number of question record for query message or 562da6c28aaSamw * number of zone record for update message 563da6c28aaSamw * ans_prereq_cnt : number of answer record for query message or 564da6c28aaSamw * number of prerequisite record for update message 565da6c28aaSamw * nameser_update_cnt: number of name server for query message or 566da6c28aaSamw * number of update record for update message 567da6c28aaSamw * addit_cnt : number of additional record 568da6c28aaSamw * flags : query flags word 569da6c28aaSamw * Returns: 570da6c28aaSamw * ptr: address of pointer to next available buffer space 571da6c28aaSamw * -1 : error 572da6c28aaSamw * 0 : success 573da6c28aaSamw */ 5743db3f65cSamw static int 575da6c28aaSamw dyndns_build_header(char **ptr, int buf_len, uint16_t msg_id, int query_req, 576da6c28aaSamw uint16_t quest_zone_cnt, uint16_t ans_prereq_cnt, 577da6c28aaSamw uint16_t nameser_update_cnt, uint16_t addit_cnt, int flags) 578da6c28aaSamw { 579da6c28aaSamw uint16_t opcode; 580da6c28aaSamw 581da6c28aaSamw if (buf_len < 12) { 5828d7e4166Sjose borrego syslog(LOG_ERR, "dyndns header section: buffer too small"); 583da6c28aaSamw return (-1); 584da6c28aaSamw } 585da6c28aaSamw 586da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, msg_id); /* mesg ID */ 587da6c28aaSamw if (query_req == REQ_QUERY) 588da6c28aaSamw opcode = ns_o_query; /* query msg */ 589da6c28aaSamw else 590da6c28aaSamw opcode = ns_o_update << 11; /* update msg */ 591da6c28aaSamw opcode |= flags; 592da6c28aaSamw /* mesg opcode */ 593da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, opcode); 594da6c28aaSamw /* zone record count */ 595da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, quest_zone_cnt); 596da6c28aaSamw /* prerequiste record count */ 597da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, ans_prereq_cnt); 598da6c28aaSamw /* update record count */ 599da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, nameser_update_cnt); 600da6c28aaSamw /* additional record count */ 601da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, addit_cnt); 602da6c28aaSamw 603da6c28aaSamw return (0); 604da6c28aaSamw } 605da6c28aaSamw 606da6c28aaSamw /* 607da6c28aaSamw * dyndns_build_quest_zone 608da6c28aaSamw * Build the question section for query message or zone section for 609da6c28aaSamw * update message. 610da6c28aaSamw * Parameters: 611da6c28aaSamw * ptr : address of pointer to buffer to store question or zone section 612da6c28aaSamw * buf_len: buffer length 613da6c28aaSamw * name : question or zone name 614da6c28aaSamw * type : type of question or zone 615da6c28aaSamw * class : class of question or zone 616da6c28aaSamw * Returns: 617da6c28aaSamw * ptr: address of pointer to next available buffer space 618da6c28aaSamw * -1 : error 619da6c28aaSamw * 0 : success 620da6c28aaSamw */ 6213db3f65cSamw static int 622da6c28aaSamw dyndns_build_quest_zone(char **ptr, int buf_len, char *name, int type, 623da6c28aaSamw int class) 624da6c28aaSamw { 625da6c28aaSamw char *zonePtr; 626da6c28aaSamw 627da6c28aaSamw if ((strlen(name) + 6) > buf_len) { 6288d7e4166Sjose borrego syslog(LOG_ERR, "dyndns question section: buffer too small"); 629da6c28aaSamw return (-1); 630da6c28aaSamw } 631da6c28aaSamw 632da6c28aaSamw zonePtr = *ptr; 633da6c28aaSamw (void) dyndns_stuff_str(&zonePtr, name); 634da6c28aaSamw *ptr = zonePtr; 635da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, type); 636da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, class); 637da6c28aaSamw return (0); 638da6c28aaSamw } 639da6c28aaSamw 640da6c28aaSamw /* 641da6c28aaSamw * dyndns_build_update 642da6c28aaSamw * Build update section of update message for adding and removing a record. 643da6c28aaSamw * If the ttl value is 0 then this message is for record deletion. 644da6c28aaSamw * 645da6c28aaSamw * Parameters: 646da6c28aaSamw * ptr : address of pointer to buffer to store update section 647da6c28aaSamw * buf_len : buffer length 648da6c28aaSamw * name : resource name of this record 649da6c28aaSamw * type : type of this record 650da6c28aaSamw * class : class of this record 651da6c28aaSamw * ttl : time-to-live, cached time of this entry by others and not 652da6c28aaSamw * within DNS database, a zero value for record(s) deletion 653da6c28aaSamw * data : data of this resource record 654da6c28aaSamw * forw_rev: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 655da6c28aaSamw * add_del : UPDATE_ADD for adding entry, UPDATE_DEL for removing zone 656da6c28aaSamw * del_type: DEL_ONE for deleting one entry, DEL_ALL for deleting all 657da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL. 658da6c28aaSamw * Returns: 659da6c28aaSamw * ptr: address of pointer to next available buffer space 660da6c28aaSamw * -1 : error 661da6c28aaSamw * 0 : success 662da6c28aaSamw */ 663da6c28aaSamw static int 664da6c28aaSamw dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class, 665da6c28aaSamw uint32_t ttl, char *data, int forw_rev, int add_del, int del_type) 666da6c28aaSamw { 667da6c28aaSamw char *namePtr; 668da6c28aaSamw int rec_len, data_len; 6697f667e74Sjose borrego smb_inaddr_t ipaddr; 6707f667e74Sjose borrego int isv4 = 1; 671da6c28aaSamw 672da6c28aaSamw rec_len = strlen(name) + 10; 6737f667e74Sjose borrego if (inet_pton(AF_INET, data, &ipaddr) == 1) 6747f667e74Sjose borrego isv4 = 1; 6757f667e74Sjose borrego else if (inet_pton(AF_INET6, data, &ipaddr) == 1) 6767f667e74Sjose borrego isv4 = 0; 6777f667e74Sjose borrego 678da6c28aaSamw if (add_del == UPDATE_ADD) { 679da6c28aaSamw if (forw_rev == UPDATE_FORW) 6807f667e74Sjose borrego data_len = isv4 ? 4 : 16; 681da6c28aaSamw else 682da6c28aaSamw data_len = strlen(data) + 2; 683da6c28aaSamw } else { 684da6c28aaSamw if (del_type == DEL_ALL) 685da6c28aaSamw data_len = 0; 686da6c28aaSamw else if (forw_rev == UPDATE_FORW) 6877f667e74Sjose borrego data_len = isv4 ? 4 : 16; 688da6c28aaSamw else 689da6c28aaSamw data_len = strlen(data) + 2; 690da6c28aaSamw } 691da6c28aaSamw if (rec_len + data_len > buf_len) { 6928d7e4166Sjose borrego syslog(LOG_ERR, "dyndns update section: buffer too small"); 693da6c28aaSamw return (-1); 694da6c28aaSamw } 695da6c28aaSamw 696da6c28aaSamw namePtr = *ptr; 697da6c28aaSamw (void) dyndns_stuff_str(&namePtr, name); 698da6c28aaSamw *ptr = namePtr; 6997f667e74Sjose borrego if (isv4) 700da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, type); 7017f667e74Sjose borrego else 7027f667e74Sjose borrego *ptr = dyndns_put_nshort(*ptr, ns_t_aaaa); 703da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, class); 704da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, ttl); 705da6c28aaSamw 706da6c28aaSamw if (add_del == UPDATE_DEL && del_type == DEL_ALL) { 707da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 0); 708da6c28aaSamw return (0); 709da6c28aaSamw } 710da6c28aaSamw 711da6c28aaSamw if (forw_rev == UPDATE_FORW) { 7127f667e74Sjose borrego if (isv4) { 713da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 4); 7147f667e74Sjose borrego *ptr = dyndns_put_int(*ptr, ipaddr.a_ipv4); 7157f667e74Sjose borrego } else { 7167f667e74Sjose borrego *ptr = dyndns_put_nshort(*ptr, 16); 7177f667e74Sjose borrego *ptr = dyndns_put_v6addr(*ptr, &ipaddr); 7187f667e74Sjose borrego } 719da6c28aaSamw } else { 720da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, strlen(data)+2); 721da6c28aaSamw namePtr = *ptr; 722da6c28aaSamw (void) dyndns_stuff_str(&namePtr, data); /* hostname */ 723da6c28aaSamw *ptr = namePtr; 724da6c28aaSamw } 725da6c28aaSamw return (0); 726da6c28aaSamw } 727da6c28aaSamw 728da6c28aaSamw /* 729da6c28aaSamw * dyndns_build_tkey 730da6c28aaSamw * Build TKEY section to establish security context for secure dynamic DNS 731da6c28aaSamw * update. DNS header and question sections need to be build before this 732da6c28aaSamw * section. The TKEY data are the tokens generated during security context 733da6c28aaSamw * establishment and the TKEY message is used to transmit those tokens, one 734da6c28aaSamw * at a time, to the DNS server. 735da6c28aaSamw * Parameters: 736da6c28aaSamw * ptr : address of pointer to buffer to store TKEY 737da6c28aaSamw * buf_len : buffer length 738da6c28aaSamw * name : key name, must be unique and same as for TSIG record 739da6c28aaSamw * key_expire: expiration time of this key in second 740da6c28aaSamw * data : TKEY data 741da6c28aaSamw * data_size : data size 742da6c28aaSamw * Returns: 743da6c28aaSamw * ptr: address of the pointer to the next available buffer space 744da6c28aaSamw * -1 : error 745da6c28aaSamw * 0 : success 746da6c28aaSamw */ 747da6c28aaSamw static int 748da6c28aaSamw dyndns_build_tkey(char **ptr, int buf_len, char *name, int key_expire, 749da6c28aaSamw char *data, int data_size) 750da6c28aaSamw { 751da6c28aaSamw char *namePtr; 752da6c28aaSamw struct timeval tp; 753da6c28aaSamw 754da6c28aaSamw if (strlen(name)+2 + 45 + data_size > buf_len) { 7558d7e4166Sjose borrego syslog(LOG_ERR, "dyndns TKEY: buffer too small"); 756da6c28aaSamw return (-1); 757da6c28aaSamw } 758da6c28aaSamw 759da6c28aaSamw namePtr = *ptr; 760da6c28aaSamw (void) dyndns_stuff_str(&namePtr, name); /* unique global name */ 761da6c28aaSamw *ptr = namePtr; 762da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, ns_t_tkey); 763da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, ns_c_any); 764da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, 0); 765da6c28aaSamw /* 19 + 14 + data_size + 2 */ 766da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 35 + data_size); 767da6c28aaSamw namePtr = *ptr; 768da6c28aaSamw (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com"); 769da6c28aaSamw *ptr = namePtr; 770da6c28aaSamw (void) gettimeofday(&tp, 0); 771da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, tp.tv_sec); /* inception */ 772da6c28aaSamw /* expiration, 86400 */ 773da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, tp.tv_sec + key_expire); 774da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, MODE_GSS_API); /* mode: gss-api */ 775da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 0); /* error */ 776da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, data_size); /* key size */ 777da6c28aaSamw (void) memcpy(*ptr, data, data_size); /* key data */ 778da6c28aaSamw *ptr += data_size; 779da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 0); /* other */ 780da6c28aaSamw return (0); 781da6c28aaSamw } 782da6c28aaSamw 783da6c28aaSamw /* 784da6c28aaSamw * dyndns_build_tsig 785da6c28aaSamw * Build TSIG section for secure dynamic DNS update. This routine will be 786da6c28aaSamw * called twice. First called with TSIG_UNSIGNED, and second with TSIG_SIGNED. 787da6c28aaSamw * The TSIG data is NULL and ignored for TSIG_UNSIGNED and is the update request 788da6c28aaSamw * message encrypted for TSIG_SIGNED. The message id must be the same id as the 789da6c28aaSamw * one in the update request before it is encrypted. 790da6c28aaSamw * Parameters: 791da6c28aaSamw * ptr : address of pointer to buffer to store TSIG 792da6c28aaSamw * buf_len : buffer length 793da6c28aaSamw * msg_id : message id 794da6c28aaSamw * name : key name, must be the same as in TKEY record 795da6c28aaSamw * fudge_time : amount of error time allow in seconds 796da6c28aaSamw * data : TSIG data if TSIG_SIGNED, otherwise NULL 797da6c28aaSamw * data_size : size of data, otherwise 0 if data is NULL 798da6c28aaSamw * data_signed: TSIG_SIGNED to indicate data is signed and encrypted, 799da6c28aaSamw * otherwise TSIG_UNSIGNED 800da6c28aaSamw * Returns: 801da6c28aaSamw * ptr: address of pointer to next available buffer space 802da6c28aaSamw * -1 : error 803da6c28aaSamw * 0 : success 804da6c28aaSamw */ 805da6c28aaSamw static int 806da6c28aaSamw dyndns_build_tsig(char **ptr, int buf_len, int msg_id, char *name, 807da6c28aaSamw int fudge_time, char *data, int data_size, int data_signed) 808da6c28aaSamw { 809da6c28aaSamw char *namePtr; 810da6c28aaSamw struct timeval tp; 811da6c28aaSamw int signtime, fudge, rec_len; 812da6c28aaSamw 813da6c28aaSamw if (data_signed == TSIG_UNSIGNED) 814da6c28aaSamw rec_len = strlen(name)+2 + 37; 815da6c28aaSamw else 816da6c28aaSamw rec_len = strlen(name)+2 + 45 + data_size; 817da6c28aaSamw 818da6c28aaSamw if (rec_len > buf_len) { 8198d7e4166Sjose borrego syslog(LOG_ERR, "dyndns TSIG: buffer too small"); 820da6c28aaSamw return (-1); 821da6c28aaSamw } 822da6c28aaSamw 823da6c28aaSamw namePtr = *ptr; 824da6c28aaSamw (void) dyndns_stuff_str(&namePtr, name); /* unique global name */ 825da6c28aaSamw *ptr = namePtr; 826da6c28aaSamw if (data_signed == TSIG_SIGNED) 827da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, ns_t_tsig); 828da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, ns_c_any); 829da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, 0); 830da6c28aaSamw if (data_signed == TSIG_SIGNED) { 831da6c28aaSamw /* 19 + 10 + data_size + 6 */ 832da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 35 + data_size); 833da6c28aaSamw } 834da6c28aaSamw namePtr = *ptr; 835da6c28aaSamw (void) dyndns_stuff_str(&namePtr, "gss.microsoft.com"); 836da6c28aaSamw *ptr = namePtr; 837da6c28aaSamw (void) gettimeofday(&tp, 0); 838da6c28aaSamw signtime = tp.tv_sec >> 16; 839da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, signtime); /* sign time */ 840da6c28aaSamw fudge = tp.tv_sec << 16; 841da6c28aaSamw fudge |= fudge_time; 842da6c28aaSamw *ptr = dyndns_put_nlong(*ptr, fudge); /* fudge time */ 843da6c28aaSamw if (data_signed == TSIG_SIGNED) { 844da6c28aaSamw /* signed data size */ 845da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, data_size); 846da6c28aaSamw (void) memcpy(*ptr, data, data_size); /* signed data */ 847da6c28aaSamw *ptr += data_size; 848da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, msg_id); /* original id */ 849da6c28aaSamw } 850da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 0); /* error */ 851da6c28aaSamw *ptr = dyndns_put_nshort(*ptr, 0); /* other */ 852da6c28aaSamw return (0); 853da6c28aaSamw } 854da6c28aaSamw 855da6c28aaSamw /* 856da6c28aaSamw * dyndns_open_init_socket 857da6c28aaSamw * This routine creates a SOCK_STREAM or SOCK_DGRAM socket and initializes it 858da6c28aaSamw * by doing bind() and setting linger option to off. 859da6c28aaSamw * 860da6c28aaSamw * Parameters: 861da6c28aaSamw * sock_type: SOCK_STREAM for TCP or SOCK_DGRAM for UDP 862da6c28aaSamw * dest_addr: destination address in network byte order 863da6c28aaSamw * port : destination port number 864da6c28aaSamw * Returns: 865da6c28aaSamw * descriptor: descriptor referencing the created socket 866da6c28aaSamw * -1 : error 867da6c28aaSamw */ 8687f667e74Sjose borrego 8693db3f65cSamw static int 8707f667e74Sjose borrego dyndns_open_init_socket(int sock_type, smb_inaddr_t *dest_addr, int port) 871da6c28aaSamw { 872da6c28aaSamw int s; 873da6c28aaSamw struct sockaddr_in my_addr; 8747f667e74Sjose borrego struct sockaddr_in6 my6_addr; 875da6c28aaSamw struct sockaddr_in serv_addr; 8767f667e74Sjose borrego struct sockaddr_in6 serv6_addr; 8777f667e74Sjose borrego int family; 878da6c28aaSamw 8797f667e74Sjose borrego family = dest_addr->a_family; 8807f667e74Sjose borrego 8817f667e74Sjose borrego if ((s = socket(family, sock_type, 0)) == -1) { 8827f667e74Sjose borrego syslog(LOG_ERR, "dyndns: socket error\n"); 883da6c28aaSamw return (-1); 884da6c28aaSamw } 8857f667e74Sjose borrego if (family == AF_INET) { 886da6c28aaSamw bzero(&my_addr, sizeof (my_addr)); 8877f667e74Sjose borrego my_addr.sin_family = family; 888da6c28aaSamw my_addr.sin_port = htons(0); 889da6c28aaSamw my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 8907f667e74Sjose borrego if (bind(s, (struct sockaddr *)&my_addr, 8917f667e74Sjose borrego sizeof (my_addr)) < 0) { 8927f667e74Sjose borrego syslog(LOG_ERR, "dyndns: client bind err\n"); 893da6c28aaSamw (void) close(s); 894da6c28aaSamw return (-1); 895da6c28aaSamw } 8967f667e74Sjose borrego serv_addr.sin_family = family; 897da6c28aaSamw serv_addr.sin_port = htons(port); 8987f667e74Sjose borrego serv_addr.sin_addr.s_addr = dest_addr->a_ipv4; 899da6c28aaSamw if (connect(s, (struct sockaddr *)&serv_addr, 900da6c28aaSamw sizeof (struct sockaddr_in)) < 0) { 9017f667e74Sjose borrego syslog(LOG_ERR, "dyndns: client connect (%s)\n", 902da6c28aaSamw strerror(errno)); 903da6c28aaSamw (void) close(s); 904da6c28aaSamw return (-1); 905da6c28aaSamw } 9067f667e74Sjose borrego } else { 9077f667e74Sjose borrego bzero(&my6_addr, sizeof (my6_addr)); 9087f667e74Sjose borrego my6_addr.sin6_family = family; 9097f667e74Sjose borrego my6_addr.sin6_port = htons(0); 9107f667e74Sjose borrego bzero(&my6_addr.sin6_addr.s6_addr, IN6ADDRSZ); 9117f667e74Sjose borrego if (bind(s, (struct sockaddr *)&my6_addr, 9127f667e74Sjose borrego sizeof (my6_addr)) < 0) { 9137f667e74Sjose borrego syslog(LOG_ERR, "dyndns: client bind err\n"); 9147f667e74Sjose borrego (void) close(s); 9157f667e74Sjose borrego return (-1); 9167f667e74Sjose borrego } 9177f667e74Sjose borrego serv6_addr.sin6_family = family; 9187f667e74Sjose borrego serv6_addr.sin6_port = htons(port); 9197f667e74Sjose borrego bcopy(&serv6_addr.sin6_addr.s6_addr, &dest_addr->a_ipv6, 9207f667e74Sjose borrego IN6ADDRSZ); 9217f667e74Sjose borrego if (connect(s, (struct sockaddr *)&serv6_addr, 9227f667e74Sjose borrego sizeof (struct sockaddr_in6)) < 0) { 9237f667e74Sjose borrego syslog(LOG_ERR, "dyndns: client connect err (%s)\n", 9247f667e74Sjose borrego strerror(errno)); 9257f667e74Sjose borrego (void) close(s); 9267f667e74Sjose borrego return (-1); 9277f667e74Sjose borrego } 9287f667e74Sjose borrego } 929da6c28aaSamw return (s); 930da6c28aaSamw } 931da6c28aaSamw /* 932da6c28aaSamw * dyndns_build_tkey_msg 933da6c28aaSamw * This routine is used to build the TKEY message to transmit GSS tokens 934da6c28aaSamw * during GSS security context establishment for secure DNS update. The 935da6c28aaSamw * TKEY message format uses the DNS query message format. The TKEY section 936da6c28aaSamw * is the answer section of the query message format. 937da6c28aaSamw * Microsoft uses a value of 86400 seconds (24 hours) for key expiration time. 938da6c28aaSamw * Parameters: 939da6c28aaSamw * buf : buffer to build and store TKEY message 940da6c28aaSamw * key_name: a unique key name, this same key name must be also be used in 941da6c28aaSamw * the TSIG message 942da6c28aaSamw * out_tok : TKEY message data (GSS tokens) 943da6c28aaSamw * Returns: 944da6c28aaSamw * id : message id of this TKEY message 945da6c28aaSamw * message size: the size of the TKEY message 946da6c28aaSamw * -1 : error 947da6c28aaSamw */ 948da6c28aaSamw static int 949da6c28aaSamw dyndns_build_tkey_msg(char *buf, char *key_name, uint16_t *id, 950da6c28aaSamw gss_buffer_desc *out_tok) 951da6c28aaSamw { 952da6c28aaSamw int queryReq, zoneCount, preqCount, updateCount, additionalCount; 953da6c28aaSamw int zoneType, zoneClass; 954da6c28aaSamw char *bufptr; 955da6c28aaSamw 956da6c28aaSamw queryReq = REQ_QUERY; 957da6c28aaSamw /* query section of query request */ 958da6c28aaSamw zoneCount = 1; 959da6c28aaSamw /* answer section of query request */ 960da6c28aaSamw preqCount = 1; 961da6c28aaSamw updateCount = 0; 962da6c28aaSamw additionalCount = 0; 963da6c28aaSamw 964da6c28aaSamw (void) memset(buf, 0, MAX_TCP_SIZE); 965da6c28aaSamw bufptr = buf; 9668d7e4166Sjose borrego *id = dyndns_get_msgid(); 967da6c28aaSamw 968da6c28aaSamw /* add TCP length info that follows this field */ 969da6c28aaSamw bufptr = dyndns_put_nshort(bufptr, 970da6c28aaSamw 26 + (strlen(key_name)+2)*2 + 35 + out_tok->length); 971da6c28aaSamw 972da6c28aaSamw if (dyndns_build_header(&bufptr, BUFLEN_TCP(bufptr, buf), *id, queryReq, 973da6c28aaSamw zoneCount, preqCount, updateCount, additionalCount, 0) == -1) { 974da6c28aaSamw return (-1); 975da6c28aaSamw } 976da6c28aaSamw 977da6c28aaSamw zoneType = ns_t_tkey; 978da6c28aaSamw zoneClass = ns_c_in; 979da6c28aaSamw if (dyndns_build_quest_zone(&bufptr, BUFLEN_TCP(bufptr, buf), key_name, 980da6c28aaSamw zoneType, zoneClass) == -1) { 981da6c28aaSamw return (-1); 982da6c28aaSamw } 983da6c28aaSamw 984da6c28aaSamw if (dyndns_build_tkey(&bufptr, BUFLEN_TCP(bufptr, buf), key_name, 985da6c28aaSamw 86400, out_tok->value, out_tok->length) == -1) { 986da6c28aaSamw return (-1); 987da6c28aaSamw } 988da6c28aaSamw 989da6c28aaSamw return (bufptr - buf); 990da6c28aaSamw } 991da6c28aaSamw 992da6c28aaSamw /* 993da6c28aaSamw * dyndns_establish_sec_ctx 994da6c28aaSamw * This routine is used to establish a security context with the DNS server 995da6c28aaSamw * by building TKEY messages and sending them to the DNS server. TKEY messages 996da6c28aaSamw * are also received from the DNS server for processing. The security context 997da6c28aaSamw * establishment is done with the GSS client on the system producing a token 998da6c28aaSamw * and sending the token within the TKEY message to the GSS server on the DNS 999da6c28aaSamw * server. The GSS server then processes the token and then send a TKEY reply 1000da6c28aaSamw * message with a new token to be processed by the GSS client. The GSS client 1001da6c28aaSamw * processes the new token and then generates a new token to be sent to the 1002da6c28aaSamw * GSS server. This cycle is continued until the security establishment is 1003da6c28aaSamw * done. TCP is used to send and receive TKEY messages. 1004da6c28aaSamw * Parameters: 100555bf511dSas200622 * cred_handle : handle to credential 1006da6c28aaSamw * s : socket descriptor to DNS server 1007da6c28aaSamw * key_name : TKEY key name 10089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * dns_hostname: fully qualified DNS hostname which will be used for 10099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * constructing the DNS service principal name. 1010da6c28aaSamw * oid : contains Kerberos 5 object identifier 1011da6c28aaSamw * Returns: 1012da6c28aaSamw * gss_context : handle to security context 1013da6c28aaSamw */ 1014da6c28aaSamw static int 101555bf511dSas200622 dyndns_establish_sec_ctx(gss_ctx_id_t *gss_context, gss_cred_id_t cred_handle, 101655bf511dSas200622 int s, char *key_name, char *dns_hostname, gss_OID oid) 1017da6c28aaSamw { 1018da6c28aaSamw uint16_t id, rid, rsz; 1019da6c28aaSamw char buf[MAX_TCP_SIZE], buf2[MAX_TCP_SIZE]; 1020da6c28aaSamw int ret; 1021da6c28aaSamw char *service_name, *tmpptr; 1022da6c28aaSamw int service_sz; 1023da6c28aaSamw OM_uint32 min, maj, time_rec; 1024da6c28aaSamw gss_buffer_desc service_buf, in_tok, out_tok; 1025da6c28aaSamw gss_name_t target_name; 1026da6c28aaSamw gss_buffer_desc *inputptr; 1027da6c28aaSamw int gss_flags; 1028da6c28aaSamw OM_uint32 ret_flags; 1029da6c28aaSamw int buf_sz; 1030da6c28aaSamw 1031da6c28aaSamw service_sz = strlen(dns_hostname) + 5; 1032da6c28aaSamw service_name = (char *)malloc(sizeof (char) * service_sz); 10338d7e4166Sjose borrego if (service_name == NULL) 1034da6c28aaSamw return (-1); 10358d7e4166Sjose borrego 1036da6c28aaSamw (void) snprintf(service_name, service_sz, "DNS@%s", dns_hostname); 1037da6c28aaSamw service_buf.value = service_name; 1038da6c28aaSamw service_buf.length = strlen(service_name)+1; 1039da6c28aaSamw if ((maj = gss_import_name(&min, &service_buf, 104055bf511dSas200622 GSS_C_NT_HOSTBASED_SERVICE, &target_name)) != GSS_S_COMPLETE) { 1041da6c28aaSamw display_stat(maj, min); 1042da6c28aaSamw (void) free(service_name); 1043da6c28aaSamw return (-1); 1044da6c28aaSamw } 1045da6c28aaSamw (void) free(service_name); 1046da6c28aaSamw 1047da6c28aaSamw inputptr = GSS_C_NO_BUFFER; 1048da6c28aaSamw *gss_context = GSS_C_NO_CONTEXT; 1049da6c28aaSamw gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | GSS_C_REPLAY_FLAG | 1050da6c28aaSamw GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG; 1051da6c28aaSamw do { 105255bf511dSas200622 maj = gss_init_sec_context(&min, cred_handle, gss_context, 105355bf511dSas200622 target_name, oid, gss_flags, 0, NULL, inputptr, NULL, 105455bf511dSas200622 &out_tok, &ret_flags, &time_rec); 105555bf511dSas200622 105655bf511dSas200622 if (maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) { 105755bf511dSas200622 assert(gss_context); 105855bf511dSas200622 if (*gss_context != GSS_C_NO_CONTEXT) 105955bf511dSas200622 (void) gss_delete_sec_context(&min, 106055bf511dSas200622 gss_context, NULL); 106155bf511dSas200622 106255bf511dSas200622 display_stat(maj, min); 1063da6c28aaSamw (void) gss_release_name(&min, &target_name); 1064da6c28aaSamw return (-1); 1065da6c28aaSamw } 1066da6c28aaSamw 1067da6c28aaSamw if ((maj == GSS_S_COMPLETE) && 1068da6c28aaSamw !(ret_flags & GSS_C_REPLAY_FLAG)) { 10698d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: No GSS_C_REPLAY_FLAG"); 1070da6c28aaSamw if (out_tok.length > 0) 1071da6c28aaSamw (void) gss_release_buffer(&min, &out_tok); 1072da6c28aaSamw (void) gss_release_name(&min, &target_name); 1073da6c28aaSamw return (-1); 1074da6c28aaSamw } 1075da6c28aaSamw 1076da6c28aaSamw if ((maj == GSS_S_COMPLETE) && 1077da6c28aaSamw !(ret_flags & GSS_C_MUTUAL_FLAG)) { 10788d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: No GSS_C_MUTUAL_FLAG"); 1079da6c28aaSamw if (out_tok.length > 0) 1080da6c28aaSamw (void) gss_release_buffer(&min, &out_tok); 1081da6c28aaSamw (void) gss_release_name(&min, &target_name); 1082da6c28aaSamw return (-1); 1083da6c28aaSamw } 1084da6c28aaSamw 1085da6c28aaSamw if (out_tok.length > 0) { 1086da6c28aaSamw if ((buf_sz = dyndns_build_tkey_msg(buf, key_name, 1087da6c28aaSamw &id, &out_tok)) <= 0) { 1088da6c28aaSamw (void) gss_release_buffer(&min, &out_tok); 1089da6c28aaSamw (void) gss_release_name(&min, &target_name); 1090da6c28aaSamw return (-1); 1091da6c28aaSamw } 1092da6c28aaSamw 1093da6c28aaSamw (void) gss_release_buffer(&min, &out_tok); 1094da6c28aaSamw 1095da6c28aaSamw if (send(s, buf, buf_sz, 0) == -1) { 10968d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: TKEY send error"); 1097da6c28aaSamw (void) gss_release_name(&min, &target_name); 1098da6c28aaSamw return (-1); 1099da6c28aaSamw } 1100da6c28aaSamw 1101da6c28aaSamw bzero(buf2, MAX_TCP_SIZE); 1102da6c28aaSamw if (recv(s, buf2, MAX_TCP_SIZE, 0) == -1) { 11038d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: TKEY recv error"); 1104da6c28aaSamw (void) gss_release_name(&min, &target_name); 1105da6c28aaSamw return (-1); 1106da6c28aaSamw } 1107da6c28aaSamw 1108da6c28aaSamw ret = buf2[5] & 0xf; /* error field in TCP */ 1109da6c28aaSamw if (ret != NOERROR) { 11108d7e4166Sjose borrego dyndns_syslog(LOG_ERR, ret, "TKEY reply"); 1111da6c28aaSamw (void) gss_release_name(&min, &target_name); 1112da6c28aaSamw return (-1); 1113da6c28aaSamw } 1114da6c28aaSamw 1115da6c28aaSamw tmpptr = &buf2[2]; 1116da6c28aaSamw (void) dyndns_get_nshort(tmpptr, &rid); 1117da6c28aaSamw if (id != rid) { 1118da6c28aaSamw (void) gss_release_name(&min, &target_name); 1119da6c28aaSamw return (-1); 1120da6c28aaSamw } 1121da6c28aaSamw 1122da6c28aaSamw tmpptr = &buf2[59+(strlen(key_name)+2)*2]; 1123da6c28aaSamw (void) dyndns_get_nshort(tmpptr, &rsz); 1124da6c28aaSamw in_tok.length = rsz; 1125da6c28aaSamw 1126da6c28aaSamw /* bsd38 -> 2*7=14 */ 1127da6c28aaSamw in_tok.value = &buf2[61+(strlen(key_name)+2)*2]; 1128da6c28aaSamw inputptr = &in_tok; 1129da6c28aaSamw } 1130da6c28aaSamw 1131da6c28aaSamw } while (maj != GSS_S_COMPLETE); 1132da6c28aaSamw 1133da6c28aaSamw (void) gss_release_name(&min, &target_name); 1134da6c28aaSamw 1135da6c28aaSamw return (0); 1136da6c28aaSamw } 1137da6c28aaSamw 1138da6c28aaSamw /* 1139da6c28aaSamw * dyndns_get_sec_context 1140da6c28aaSamw * Get security context for secure dynamic DNS update. This routine opens 114155bf511dSas200622 * a TCP socket to the DNS server and establishes a security context with 114255bf511dSas200622 * the DNS server using host principal to perform secure dynamic DNS update. 1143da6c28aaSamw * Parameters: 1144da6c28aaSamw * hostname: fully qualified hostname 1145da6c28aaSamw * dns_ip : ip address of hostname in network byte order 1146da6c28aaSamw * Returns: 1147da6c28aaSamw * gss_handle: gss credential handle 1148da6c28aaSamw * gss_context: gss security context 1149da6c28aaSamw * -1: error 1150da6c28aaSamw * 0: success 1151da6c28aaSamw */ 11527f667e74Sjose borrego 1153da6c28aaSamw static gss_ctx_id_t 11547f667e74Sjose borrego dyndns_get_sec_context(const char *hostname, smb_inaddr_t *dns_ip) 1155da6c28aaSamw { 1156da6c28aaSamw int s; 115755bf511dSas200622 gss_cred_id_t cred_handle; 1158da6c28aaSamw gss_ctx_id_t gss_context; 1159da6c28aaSamw gss_OID oid; 116055bf511dSas200622 char *key_name, dns_hostname[MAXHOSTNAMELEN]; 1161da6c28aaSamw 116255bf511dSas200622 cred_handle = GSS_C_NO_CREDENTIAL; 116355bf511dSas200622 oid = GSS_C_NO_OID; 1164da6c28aaSamw key_name = (char *)hostname; 1165da6c28aaSamw 116629bd2886SAlan Wright if (smb_getnameinfo(dns_ip, dns_hostname, 11677f667e74Sjose borrego sizeof (dns_hostname), 0)) { 1168da6c28aaSamw return (NULL); 1169da6c28aaSamw } 1170da6c28aaSamw if ((s = dyndns_open_init_socket(SOCK_STREAM, dns_ip, 53)) < 0) { 1171da6c28aaSamw return (NULL); 1172da6c28aaSamw } 1173da6c28aaSamw 117455bf511dSas200622 if (dyndns_establish_sec_ctx(&gss_context, cred_handle, s, key_name, 117555bf511dSas200622 dns_hostname, oid)) 117655bf511dSas200622 gss_context = NULL; 1177da6c28aaSamw 1178da6c28aaSamw (void) close(s); 1179da6c28aaSamw return (gss_context); 1180da6c28aaSamw } 1181da6c28aaSamw 1182da6c28aaSamw /* 1183da6c28aaSamw * dyndns_build_add_remove_msg 1184da6c28aaSamw * This routine builds the update request message for adding and removing DNS 1185da6c28aaSamw * entries which is used for non-secure and secure DNS update. 1186da6c28aaSamw * This routine builds an UDP message. 1187da6c28aaSamw * Parameters: 1188da6c28aaSamw * buf : buffer to build message 1189da6c28aaSamw * update_zone: the type of zone to update, use UPDATE_FORW for forward 1190da6c28aaSamw * lookup zone, use UPDATE_REV for reverse lookup zone 1191da6c28aaSamw * hostname : fully qualified hostname to update DNS with 1192da6c28aaSamw * ip_addr : IP address of hostname 1193da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1194da6c28aaSamw * database 1195da6c28aaSamw * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1196da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1197da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL. 1198da6c28aaSamw * addit_cnt : Indicate how many record is in the additional section of 1199da6c28aaSamw * the DNS message. A value of zero is always used with 1200da6c28aaSamw * non-secure update message. For secure update message, 1201da6c28aaSamw * the value will be one because the signed TSIG message 1202da6c28aaSamw * is added as the additional record of the DNS update message. 1203da6c28aaSamw * id : DNS message ID. If a positive value then this ID value is 1204da6c28aaSamw * used, otherwise the next incremented value is used 1205da6c28aaSamw * level : This is the domain level which we send the request to, level 1206da6c28aaSamw * zero is the default level, it can go upto 2 in reverse zone 1207da6c28aaSamw * and virtually to any level in forward zone. 1208da6c28aaSamw * Returns: 1209da6c28aaSamw * buf : buffer containing update message 1210da6c28aaSamw * id : DNS message ID 1211da6c28aaSamw * int : size of update message 1212da6c28aaSamw * -1 : error 1213da6c28aaSamw * 1214da6c28aaSamw * This function is changed to handle dynamic DNS update retires to higher 1215da6c28aaSamw * authoritative domains. 1216da6c28aaSamw */ 1217da6c28aaSamw static int 1218da6c28aaSamw dyndns_build_add_remove_msg(char *buf, int update_zone, const char *hostname, 1219da6c28aaSamw const char *ip_addr, int life_time, int update_type, int del_type, 1220da6c28aaSamw int addit_cnt, uint16_t *id, int level) 1221da6c28aaSamw { 1222da6c28aaSamw int a, b, c, d; 1223da6c28aaSamw char *bufptr; 1224da6c28aaSamw int queryReq, zoneCount, preqCount, updateCount, additionalCount; 1225da6c28aaSamw char *zone, *resource, *data, zone_buf[100], resrc_buf[100]; 1226da6c28aaSamw int zoneType, zoneClass, type, class, ttl; 1227da6c28aaSamw char *p; 12287f667e74Sjose borrego smb_inaddr_t tmp_addr; 12297f667e74Sjose borrego int i, j, k; 12307f667e74Sjose borrego int fourcnt; 1231da6c28aaSamw 1232da6c28aaSamw queryReq = REQ_UPDATE; 1233da6c28aaSamw zoneCount = 1; 1234da6c28aaSamw preqCount = 0; 1235da6c28aaSamw updateCount = 1; 1236da6c28aaSamw additionalCount = addit_cnt; 1237da6c28aaSamw 1238da6c28aaSamw (void) memset(buf, 0, NS_PACKETSZ); 1239da6c28aaSamw bufptr = buf; 1240da6c28aaSamw 1241da6c28aaSamw if (*id == 0) 12428d7e4166Sjose borrego *id = dyndns_get_msgid(); 1243da6c28aaSamw 1244da6c28aaSamw if (dyndns_build_header(&bufptr, BUFLEN_UDP(bufptr, buf), *id, queryReq, 1245da6c28aaSamw zoneCount, preqCount, updateCount, additionalCount, 0) == -1) { 1246da6c28aaSamw return (-1); 1247da6c28aaSamw } 1248da6c28aaSamw 1249da6c28aaSamw zoneType = ns_t_soa; 1250da6c28aaSamw zoneClass = ns_c_in; 1251da6c28aaSamw 1252da6c28aaSamw if (update_zone == UPDATE_FORW) { 1253da6c28aaSamw p = (char *)hostname; 1254da6c28aaSamw 1255da6c28aaSamw /* Try higher domains according to the level requested */ 1256da6c28aaSamw do { 1257da6c28aaSamw /* domain */ 1258da6c28aaSamw if ((zone = (char *)strchr(p, '.')) == NULL) 1259da6c28aaSamw return (-1); 1260da6c28aaSamw zone += 1; 1261da6c28aaSamw p = zone; 1262da6c28aaSamw } while (--level >= 0); 1263da6c28aaSamw resource = (char *)hostname; 1264da6c28aaSamw data = (char *)ip_addr; 1265da6c28aaSamw } else { 12667f667e74Sjose borrego if (inet_pton(AF_INET, ip_addr, &tmp_addr) == 1) { 1267da6c28aaSamw (void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d); 12687f667e74Sjose borrego (void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", 12697f667e74Sjose borrego c, b, a); 1270da6c28aaSamw zone = p = zone_buf; 1271da6c28aaSamw 12727f667e74Sjose borrego /* Try higher domains based on level requested */ 1273da6c28aaSamw while (--level >= 0) { 1274da6c28aaSamw /* domain */ 1275da6c28aaSamw if ((zone = (char *)strchr(p, '.')) == NULL) { 1276da6c28aaSamw return (-1); 1277da6c28aaSamw } 1278da6c28aaSamw zone += 1; 1279da6c28aaSamw p = zone; 1280da6c28aaSamw } 1281da6c28aaSamw (void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa", 1282da6c28aaSamw d, c, b, a); 12837f667e74Sjose borrego } else { 12847f667e74Sjose borrego /* 12857f667e74Sjose borrego * create reverse nibble ipv6 format 12867f667e74Sjose borrego */ 12877f667e74Sjose borrego bzero(resrc_buf, 100); 12887f667e74Sjose borrego i = 0; 12897f667e74Sjose borrego j = 0; 12907f667e74Sjose borrego while (ip_addr[i] != 0) 12917f667e74Sjose borrego i++; 12927f667e74Sjose borrego i--; 12937f667e74Sjose borrego while (i >= 0) { 12947f667e74Sjose borrego fourcnt = 3; 12957f667e74Sjose borrego while ((i >= 0) && (ip_addr[i] != ':')) { 12967f667e74Sjose borrego resrc_buf[j++] = ip_addr[i]; 12977f667e74Sjose borrego (void) strcat(&resrc_buf[j++], "."); 12987f667e74Sjose borrego fourcnt --; 12997f667e74Sjose borrego i--; 13007f667e74Sjose borrego } 13017f667e74Sjose borrego for (k = 0; k <= fourcnt; k++) { 13027f667e74Sjose borrego resrc_buf[j++] = '0'; 13037f667e74Sjose borrego (void) strcat(&resrc_buf[j++], "."); 13047f667e74Sjose borrego } 13057f667e74Sjose borrego i--; 13067f667e74Sjose borrego } 13077f667e74Sjose borrego (void) strcat(resrc_buf, "ip6.arpa"); 13087f667e74Sjose borrego (void) strcpy(zone_buf, &resrc_buf[32]); 13097f667e74Sjose borrego zone = zone_buf; 13107f667e74Sjose borrego } 1311da6c28aaSamw resource = resrc_buf; /* ip info */ 1312da6c28aaSamw data = (char *)hostname; 1313da6c28aaSamw } 1314da6c28aaSamw if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), zone, 1315da6c28aaSamw zoneType, zoneClass) == -1) { 1316da6c28aaSamw return (-1); 1317da6c28aaSamw } 1318da6c28aaSamw 1319da6c28aaSamw if (update_zone == UPDATE_FORW) 1320da6c28aaSamw type = ns_t_a; 1321da6c28aaSamw else 1322da6c28aaSamw type = ns_t_ptr; 1323da6c28aaSamw 1324da6c28aaSamw if (update_type == UPDATE_ADD) { 1325da6c28aaSamw class = ns_c_in; 1326da6c28aaSamw ttl = life_time; 1327da6c28aaSamw } else { 1328da6c28aaSamw if (del_type == DEL_ONE) 1329da6c28aaSamw class = ns_c_none; /* remove one */ 1330da6c28aaSamw else 1331da6c28aaSamw class = ns_c_any; /* remove all */ 1332da6c28aaSamw ttl = 0; 1333da6c28aaSamw } 1334da6c28aaSamw if (dyndns_build_update(&bufptr, BUFLEN_UDP(bufptr, buf), 1335da6c28aaSamw resource, type, class, ttl, data, update_zone, 1336da6c28aaSamw update_type, del_type) == -1) { 1337da6c28aaSamw return (-1); 1338da6c28aaSamw } 1339da6c28aaSamw 1340da6c28aaSamw return (bufptr - buf); 1341da6c28aaSamw } 1342da6c28aaSamw 1343da6c28aaSamw /* 1344da6c28aaSamw * dyndns_build_unsigned_tsig_msg 1345da6c28aaSamw * This routine is used to build the unsigned TSIG message for signing. The 1346da6c28aaSamw * unsigned TSIG message contains the update request message with certain TSIG 1347da6c28aaSamw * fields included. An error time of 300 seconds is used for fudge time. This 1348da6c28aaSamw * is the number used by Microsoft clients. 1349da6c28aaSamw * This routine builds a UDP message. 1350da6c28aaSamw * Parameters: 1351da6c28aaSamw * buf : buffer to build message 1352da6c28aaSamw * update_zone: the type of zone to update, use UPDATE_FORW for forward 1353da6c28aaSamw * lookup zone, use UPDATE_REV for reverse lookup zone 1354da6c28aaSamw * hostname : fully qualified hostname to update DNS with 1355da6c28aaSamw * ip_addr : IP address of hostname 1356da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1357da6c28aaSamw * database 1358da6c28aaSamw * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1359da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1360da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL. 1361da6c28aaSamw * key_name : same key name used in TKEY message 1362da6c28aaSamw * id : DNS message ID. If a positive value then this ID value is 1363da6c28aaSamw * used, otherwise the next incremented value is used 1364da6c28aaSamw * level : This is the domain level which we send the request to, level 1365da6c28aaSamw * zero is the default level, it can go upto 2 in reverse zone 1366da6c28aaSamw * and virtually to any level in forward zone. 1367da6c28aaSamw * Returns: 1368da6c28aaSamw * buf : buffer containing update message 1369da6c28aaSamw * id : DNS message ID 1370da6c28aaSamw * int : size of update message 1371da6c28aaSamw * -1 : error 1372da6c28aaSamw */ 1373da6c28aaSamw static int 1374da6c28aaSamw dyndns_build_unsigned_tsig_msg(char *buf, int update_zone, const char *hostname, 1375da6c28aaSamw const char *ip_addr, int life_time, int update_type, int del_type, 1376da6c28aaSamw char *key_name, uint16_t *id, int level) 1377da6c28aaSamw { 1378da6c28aaSamw char *bufptr; 1379da6c28aaSamw int buf_sz; 1380da6c28aaSamw 1381da6c28aaSamw if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1382da6c28aaSamw ip_addr, life_time, update_type, del_type, 0, id, level)) <= 0) { 1383da6c28aaSamw return (-1); 1384da6c28aaSamw } 1385da6c28aaSamw 1386da6c28aaSamw bufptr = buf + buf_sz; 1387da6c28aaSamw 1388da6c28aaSamw if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf), 0, 1389da6c28aaSamw key_name, 300, NULL, 0, TSIG_UNSIGNED) == -1) { 1390da6c28aaSamw return (-1); 1391da6c28aaSamw } 1392da6c28aaSamw 1393da6c28aaSamw return (bufptr - buf); 1394da6c28aaSamw } 1395da6c28aaSamw 1396da6c28aaSamw /* 1397da6c28aaSamw * dyndns_build_signed_tsig_msg 1398da6c28aaSamw * This routine build the signed TSIG message which contains the update 1399da6c28aaSamw * request message encrypted. An error time of 300 seconds is used for fudge 1400da6c28aaSamw * time. This is the number used by Microsoft clients. 1401da6c28aaSamw * This routine builds a UDP message. 1402da6c28aaSamw * Parameters: 1403da6c28aaSamw * buf : buffer to build message 1404da6c28aaSamw * update_zone: the type of zone to update, use UPDATE_FORW for forward 1405da6c28aaSamw * lookup zone, use UPDATE_REV for reverse lookup zone 1406da6c28aaSamw * hostname : fully qualified hostname to update DNS with 1407da6c28aaSamw * ip_addr : IP address of hostname 1408da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1409da6c28aaSamw * database 1410da6c28aaSamw * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1411da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1412da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL. 1413da6c28aaSamw * key_name : same key name used in TKEY message 1414da6c28aaSamw * id : DNS message ID. If a positive value then this ID value is 1415da6c28aaSamw * used, otherwise the next incremented value is used 1416da6c28aaSamw * in_mic : the update request message encrypted 1417da6c28aaSamw * level : This is the domain level which we send the request to, level 1418da6c28aaSamw * zero is the default level, it can go upto 2 in reverse zone 1419da6c28aaSamw * and virtually to any level in forward zone. 1420da6c28aaSamw * 1421da6c28aaSamw * Returns: 1422da6c28aaSamw * buf : buffer containing update message 1423da6c28aaSamw * id : DNS message ID 1424da6c28aaSamw * int : size of update message 1425da6c28aaSamw * -1 : error 1426da6c28aaSamw */ 1427da6c28aaSamw static int 1428da6c28aaSamw dyndns_build_signed_tsig_msg(char *buf, int update_zone, const char *hostname, 1429da6c28aaSamw const char *ip_addr, int life_time, int update_type, int del_type, 1430da6c28aaSamw char *key_name, uint16_t *id, gss_buffer_desc *in_mic, int level) 1431da6c28aaSamw { 1432da6c28aaSamw char *bufptr; 1433da6c28aaSamw int buf_sz; 1434da6c28aaSamw 1435da6c28aaSamw if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1436da6c28aaSamw ip_addr, life_time, update_type, del_type, 1, id, level)) <= 0) { 1437da6c28aaSamw return (-1); 1438da6c28aaSamw } 1439da6c28aaSamw 1440da6c28aaSamw bufptr = buf + buf_sz; 1441da6c28aaSamw 1442da6c28aaSamw if (dyndns_build_tsig(&bufptr, BUFLEN_UDP(bufptr, buf), 1443da6c28aaSamw *id, key_name, 300, in_mic->value, 1444da6c28aaSamw in_mic->length, TSIG_SIGNED) == -1) { 1445da6c28aaSamw return (-1); 1446da6c28aaSamw } 1447da6c28aaSamw 1448da6c28aaSamw return (bufptr - buf); 1449da6c28aaSamw } 1450da6c28aaSamw 1451da6c28aaSamw /* 1452da6c28aaSamw * dyndns_udp_send_recv 1453dc20a302Sas200622 * This routine sends and receives UDP DNS request and reply messages. 1454da6c28aaSamw * 1455da6c28aaSamw * Pre-condition: Caller must call dyndns_open_init_socket() before calling 1456da6c28aaSamw * this function. 1457da6c28aaSamw * 1458da6c28aaSamw * Parameters: 1459da6c28aaSamw * s : socket descriptor 1460da6c28aaSamw * buf : buffer containing data to send 1461da6c28aaSamw * buf_sz : size of data to send 1462da6c28aaSamw * Returns: 1463da6c28aaSamw * -1 : error 1464da6c28aaSamw * rec_buf: reply dat 1465da6c28aaSamw * 0 : success 1466da6c28aaSamw */ 14677f667e74Sjose borrego 14683db3f65cSamw static int 1469da6c28aaSamw dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf) 1470da6c28aaSamw { 1471dc20a302Sas200622 int i, retval, addr_len; 1472da6c28aaSamw struct timeval tv, timeout; 1473da6c28aaSamw fd_set rfds; 14747f667e74Sjose borrego struct sockaddr_in6 from_addr; 1475da6c28aaSamw 1476da6c28aaSamw timeout.tv_usec = 0; 1477dc20a302Sas200622 timeout.tv_sec = DYNDNS_QUERY_TIMEOUT; 1478da6c28aaSamw 1479dc20a302Sas200622 for (i = 0; i <= DYNDNS_MAX_QUERY_RETRIES; i++) { 1480da6c28aaSamw if (send(s, buf, buf_sz, 0) == -1) { 14818d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: UDP send error (%s)", 1482da6c28aaSamw strerror(errno)); 1483da6c28aaSamw return (-1); 1484da6c28aaSamw } 1485da6c28aaSamw 1486da6c28aaSamw FD_ZERO(&rfds); 1487da6c28aaSamw FD_SET(s, &rfds); 1488da6c28aaSamw 1489da6c28aaSamw tv = timeout; 1490da6c28aaSamw 1491da6c28aaSamw retval = select(s+1, &rfds, NULL, NULL, &tv); 1492da6c28aaSamw 1493da6c28aaSamw if (retval == -1) { 1494da6c28aaSamw return (-1); 1495da6c28aaSamw } else if (retval > 0) { 1496da6c28aaSamw bzero(rec_buf, NS_PACKETSZ); 14977f667e74Sjose borrego addr_len = sizeof (struct sockaddr_in6); 1498da6c28aaSamw if (recvfrom(s, rec_buf, NS_PACKETSZ, 0, 1499da6c28aaSamw (struct sockaddr *)&from_addr, &addr_len) == -1) { 15008d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: UDP recv error "); 1501da6c28aaSamw return (-1); 1502da6c28aaSamw } 1503da6c28aaSamw break; 1504da6c28aaSamw } 1505da6c28aaSamw } 1506da6c28aaSamw 1507dc20a302Sas200622 /* did not receive anything */ 1508dc20a302Sas200622 if (i == (DYNDNS_MAX_QUERY_RETRIES + 1)) { 15098d7e4166Sjose borrego syslog(LOG_ERR, "dyndns: max retries for UDP recv reached"); 1510da6c28aaSamw return (-1); 1511da6c28aaSamw } 1512da6c28aaSamw 1513da6c28aaSamw return (0); 1514da6c28aaSamw } 1515da6c28aaSamw /* 1516da6c28aaSamw * dyndns_sec_add_remove_entry 1517da6c28aaSamw * Perform secure dynamic DNS update after getting security context. 1518da6c28aaSamw * This routine opens a UDP socket to the DNS sever, gets the security context, 1519da6c28aaSamw * builds the unsigned TSIG message and signed TSIG message. The signed TSIG 1520da6c28aaSamw * message containing the encrypted update request message is sent to the DNS 1521da6c28aaSamw * server. The response is received and check for error. If there is no 1522da6c28aaSamw * error then credential handle and security context are released and the local 1523da6c28aaSamw * NSS cached is purged. 1524da6c28aaSamw * Parameters: 1525da6c28aaSamw * update_zone : UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1526da6c28aaSamw * hostname : fully qualified hostname 1527da6c28aaSamw * ip_addr : ip address of hostname in string format 1528da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1529da6c28aaSamw * database 1530da6c28aaSamw * max_retries : maximum retries for sending DNS update request 1531da6c28aaSamw * recv_timeout: receive timeout 1532da6c28aaSamw * update_type : UPDATE_ADD for adding entry, UPDATE_DEL for removing entry 1533da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1534da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL 1535da6c28aaSamw * dns_str : DNS IP address in string format 1536da6c28aaSamw * Returns: 1537da6c28aaSamw * -1: error 1538da6c28aaSamw * 0: success 1539da6c28aaSamw * 1540da6c28aaSamw * This function is enhanced to handle the case of NOTAUTH error when DNS server 1541da6c28aaSamw * is not authoritative for specified zone. In this case we need to resend the 1542da6c28aaSamw * same request to the higher authoritative domains. 1543da6c28aaSamw * This is true for both secure and unsecure dynamic DNS updates. 1544da6c28aaSamw */ 1545da6c28aaSamw static int 1546da6c28aaSamw dyndns_sec_add_remove_entry(int update_zone, const char *hostname, 1547da6c28aaSamw const char *ip_addr, int life_time, int update_type, int del_type, 1548da6c28aaSamw char *dns_str) 1549da6c28aaSamw { 1550da6c28aaSamw int s2; 1551da6c28aaSamw uint16_t id, rid; 1552da6c28aaSamw char buf[NS_PACKETSZ], buf2[NS_PACKETSZ]; 1553da6c28aaSamw int ret; 1554da6c28aaSamw OM_uint32 min, maj; 1555da6c28aaSamw gss_buffer_desc in_mic, out_mic; 1556da6c28aaSamw gss_ctx_id_t gss_context; 15577f667e74Sjose borrego smb_inaddr_t dns_ip; 1558da6c28aaSamw char *key_name; 1559da6c28aaSamw int buf_sz; 1560da6c28aaSamw int level = 0; 1561da6c28aaSamw 1562da6c28aaSamw assert(dns_str); 1563da6c28aaSamw assert(*dns_str); 1564da6c28aaSamw 15657f667e74Sjose borrego if (inet_pton(AF_INET, dns_str, &dns_ip) == 1) 15667f667e74Sjose borrego dns_ip.a_family = AF_INET; 15677f667e74Sjose borrego else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1) 15687f667e74Sjose borrego dns_ip.a_family = AF_INET6; 1569da6c28aaSamw 1570da6c28aaSamw sec_retry_higher: 1571da6c28aaSamw 1572da6c28aaSamw if ((gss_context = dyndns_get_sec_context(hostname, 15737f667e74Sjose borrego &dns_ip)) == NULL) { 1574da6c28aaSamw return (-1); 1575da6c28aaSamw } 1576da6c28aaSamw 1577da6c28aaSamw key_name = (char *)hostname; 1578da6c28aaSamw 15797f667e74Sjose borrego if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0) { 158055bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1581da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1582da6c28aaSamw return (-1); 1583da6c28aaSamw } 1584da6c28aaSamw 1585da6c28aaSamw id = 0; 1586da6c28aaSamw if ((buf_sz = dyndns_build_unsigned_tsig_msg(buf, update_zone, hostname, 1587da6c28aaSamw ip_addr, life_time, update_type, del_type, 1588da6c28aaSamw key_name, &id, level)) <= 0) { 1589da6c28aaSamw (void) close(s2); 159055bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1591da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1592da6c28aaSamw return (-1); 1593da6c28aaSamw } 1594da6c28aaSamw 1595da6c28aaSamw in_mic.length = buf_sz; 1596da6c28aaSamw in_mic.value = buf; 1597da6c28aaSamw 1598da6c28aaSamw /* sign update message */ 1599da6c28aaSamw if ((maj = gss_get_mic(&min, gss_context, 0, &in_mic, &out_mic)) != 1600da6c28aaSamw GSS_S_COMPLETE) { 1601da6c28aaSamw display_stat(maj, min); 1602da6c28aaSamw (void) close(s2); 160355bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1604da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1605da6c28aaSamw return (-1); 1606da6c28aaSamw } 1607da6c28aaSamw 1608da6c28aaSamw if ((buf_sz = dyndns_build_signed_tsig_msg(buf, update_zone, hostname, 1609da6c28aaSamw ip_addr, life_time, update_type, del_type, key_name, &id, 1610da6c28aaSamw &out_mic, level)) <= 0) { 1611da6c28aaSamw (void) close(s2); 1612da6c28aaSamw (void) gss_release_buffer(&min, &out_mic); 161355bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1614da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1615da6c28aaSamw return (-1); 1616da6c28aaSamw } 1617da6c28aaSamw 1618da6c28aaSamw (void) gss_release_buffer(&min, &out_mic); 1619da6c28aaSamw 1620da6c28aaSamw if (dyndns_udp_send_recv(s2, buf, buf_sz, buf2)) { 1621da6c28aaSamw (void) close(s2); 162255bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1623da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1624da6c28aaSamw return (-1); 1625da6c28aaSamw } 1626da6c28aaSamw 1627da6c28aaSamw (void) close(s2); 1628da6c28aaSamw 162955bf511dSas200622 if (gss_context != GSS_C_NO_CONTEXT) 1630da6c28aaSamw (void) gss_delete_sec_context(&min, &gss_context, NULL); 1631da6c28aaSamw 1632da6c28aaSamw ret = buf2[3] & 0xf; /* error field in UDP */ 1633da6c28aaSamw 1634da6c28aaSamw /* 1635da6c28aaSamw * If it is a NOTAUTH error we should retry with higher domains 1636da6c28aaSamw * until we get a successful reply or the maximum retries is met. 1637da6c28aaSamw */ 1638da6c28aaSamw if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES) 1639da6c28aaSamw goto sec_retry_higher; 1640da6c28aaSamw 1641da6c28aaSamw /* check here for update request is successful */ 1642da6c28aaSamw if (ret != NOERROR) { 16438d7e4166Sjose borrego dyndns_syslog(LOG_ERR, ret, "TSIG reply"); 1644da6c28aaSamw return (-1); 1645da6c28aaSamw } 1646da6c28aaSamw 1647da6c28aaSamw (void) dyndns_get_nshort(buf2, &rid); 1648da6c28aaSamw if (id != rid) 1649da6c28aaSamw return (-1); 1650da6c28aaSamw 1651da6c28aaSamw return (0); 1652da6c28aaSamw } 1653da6c28aaSamw 1654da6c28aaSamw /* 1655da6c28aaSamw * dyndns_seach_entry 1656da6c28aaSamw * Query DNS server for entry. This routine can indicate if an entry exist 1657da6c28aaSamw * or not during forward or reverse lookup. Also can indicate if the data 1658da6c28aaSamw * of the entry matched. For example, for forward lookup, the entry is 1659da6c28aaSamw * searched using the hostname and the data is the IP address. For reverse 1660da6c28aaSamw * lookup, the entry is searched using the IP address and the data is the 1661da6c28aaSamw * hostname. 1662da6c28aaSamw * Parameters: 1663da6c28aaSamw * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1664da6c28aaSamw * hostname : fully qualified hostname 1665da6c28aaSamw * ip_addr : ip address of hostname in string format 1666da6c28aaSamw * update_type: UPDATE_ADD for adding entry, UPDATE_DEL for removing entry 1667da6c28aaSamw * Returns: 1668da6c28aaSamw * time_out: no use 1669da6c28aaSamw * is_match: is 1 for found matching entry, otherwise 0 1670da6c28aaSamw * 1 : an entry exist but not necessarily match 1671da6c28aaSamw * 0 : an entry does not exist 1672da6c28aaSamw */ 1673da6c28aaSamw /*ARGSUSED*/ 16747f667e74Sjose borrego 1675da6c28aaSamw static int 1676da6c28aaSamw dyndns_search_entry(int update_zone, const char *hostname, const char *ip_addr, 1677da6c28aaSamw int update_type, struct timeval *time_out, int *is_match) 1678da6c28aaSamw { 16797f667e74Sjose borrego smb_inaddr_t ipaddr, dnsip; 16807f667e74Sjose borrego char dns_hostname[NI_MAXHOST]; 16817f667e74Sjose borrego struct addrinfo hints, *res = NULL; 16827f667e74Sjose borrego int salen; 16837f667e74Sjose borrego int family; 1684da6c28aaSamw 1685da6c28aaSamw *is_match = 0; 16867f667e74Sjose borrego if (inet_pton(AF_INET, ip_addr, &ipaddr) == 1) { 16877f667e74Sjose borrego salen = sizeof (ipaddr.a_ipv4); 16887f667e74Sjose borrego family = AF_INET; 16897f667e74Sjose borrego } else if (inet_pton(AF_INET6, ip_addr, &ipaddr) == 1) { 16907f667e74Sjose borrego salen = sizeof (ipaddr.a_ipv6); 16917f667e74Sjose borrego family = AF_INET6; 16927f667e74Sjose borrego } 1693da6c28aaSamw if (update_zone == UPDATE_FORW) { 16947f667e74Sjose borrego bzero((char *)&hints, sizeof (hints)); 16957f667e74Sjose borrego hints.ai_family = family; 16967f667e74Sjose borrego hints.ai_flags = AI_NUMERICHOST; 16977f667e74Sjose borrego if (getaddrinfo(hostname, NULL, &hints, &res)) { 16987f667e74Sjose borrego return (NULL); 16997f667e74Sjose borrego } 17007f667e74Sjose borrego if (res) { 17017f667e74Sjose borrego /* 17027f667e74Sjose borrego * if both ips aren't the same family skip to 17037f667e74Sjose borrego * the next record 17047f667e74Sjose borrego */ 17057f667e74Sjose borrego do { 17067f667e74Sjose borrego if ((res->ai_family == AF_INET) && 17077f667e74Sjose borrego (family == AF_INET)) { 17087f667e74Sjose borrego (void) memcpy(&dnsip, &res->ai_addr[0], 17097f667e74Sjose borrego salen); 17107f667e74Sjose borrego if (ipaddr.a_ipv4 == 17117f667e74Sjose borrego dnsip.a_ipv4) { 17127f667e74Sjose borrego *is_match = 1; 17137f667e74Sjose borrego break; 17147f667e74Sjose borrego } 17157f667e74Sjose borrego } else if ((res->ai_family == AF_INET6) && 17167f667e74Sjose borrego (family == AF_INET6)) { 17177f667e74Sjose borrego (void) memcpy(&dnsip, &res->ai_addr[0], 17187f667e74Sjose borrego salen); 17197f667e74Sjose borrego /* need compare macro here */ 17207f667e74Sjose borrego if (!memcmp(&ipaddr, &dnsip, 17217f667e74Sjose borrego IN6ADDRSZ)) { 1722da6c28aaSamw *is_match = 1; 1723da6c28aaSamw break; 1724da6c28aaSamw } 1725da6c28aaSamw } 17267f667e74Sjose borrego } while (res->ai_next); 17277f667e74Sjose borrego freeaddrinfo(res); 1728da6c28aaSamw return (1); 1729da6c28aaSamw } 1730da6c28aaSamw } else { 173129bd2886SAlan Wright if (smb_getnameinfo(&ipaddr, dns_hostname, NI_MAXHOST, 0)) 17327f667e74Sjose borrego return (NULL); 173329bd2886SAlan Wright 17347f667e74Sjose borrego if (strncasecmp(dns_hostname, hostname, 1735da6c28aaSamw strlen(hostname)) == 0) { 1736da6c28aaSamw *is_match = 1; 1737da6c28aaSamw } 1738da6c28aaSamw return (1); 1739da6c28aaSamw } 1740da6c28aaSamw 1741da6c28aaSamw /* entry does not exist */ 1742da6c28aaSamw return (0); 1743da6c28aaSamw } 1744da6c28aaSamw 1745da6c28aaSamw /* 1746da6c28aaSamw * dyndns_add_remove_entry 1747faa1795aSjb150015 * Perform non-secure dynamic DNS update. If it fails and host principal 1748faa1795aSjb150015 * keys can be found in the local keytab file, secure update will be performed. 1749faa1795aSjb150015 * 1750da6c28aaSamw * This routine opens a UDP socket to the DNS sever, build the update request 1751da6c28aaSamw * message, and sends the message to the DNS server. The response is received 1752da6c28aaSamw * and check for error. If there is no error then the local NSS cached is 1753da6c28aaSamw * purged. DNS may be used to check to see if an entry already exist before 1754da6c28aaSamw * adding or to see if an entry does exist before removing it. Adding 1755da6c28aaSamw * duplicate entries or removing non-existing entries does not cause any 1756da6c28aaSamw * problems. DNS is not check when doing a delete all. 1757da6c28aaSamw * Parameters: 1758da6c28aaSamw * update_zone: UPDATE_FORW for forward zone, UPDATE_REV for reverse zone 1759da6c28aaSamw * hostname : fully qualified hostname 1760da6c28aaSamw * ip_addr : ip address of hostname in string format 1761da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1762da6c28aaSamw * database 1763da6c28aaSamw * update_type: UPDATE_ADD to add entry, UPDATE_DEL to remove entry 1764da6c28aaSamw * do_check : DNS_CHECK to check first in DNS, DNS_NOCHECK for no DNS 1765da6c28aaSamw * checking before update 1766da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1767da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL. 1768da6c28aaSamw * dns_str : DNS IP address in string format 1769da6c28aaSamw * Returns: 1770da6c28aaSamw * -1: error 1771da6c28aaSamw * 0: success 1772da6c28aaSamw * 1773da6c28aaSamw * This function is enhanced to handle the case of NOTAUTH error when DNS server 1774da6c28aaSamw * is not authoritative for specified zone. In this case we need to resend the 1775da6c28aaSamw * same request to the higher authoritative domains. 1776da6c28aaSamw * This is true for both secure and unsecure dynamic DNS updates. 1777da6c28aaSamw */ 1778da6c28aaSamw static int 1779da6c28aaSamw dyndns_add_remove_entry(int update_zone, const char *hostname, 1780da6c28aaSamw const char *ip_addr, int life_time, int update_type, 1781da6c28aaSamw int do_check, int del_type, char *dns_str) 1782da6c28aaSamw { 1783da6c28aaSamw int s; 1784da6c28aaSamw uint16_t id, rid; 1785da6c28aaSamw char buf[NS_PACKETSZ], buf2[NS_PACKETSZ]; 17867f667e74Sjose borrego int ret; 1787da6c28aaSamw int is_exist, is_match; 1788da6c28aaSamw struct timeval timeout; 1789da6c28aaSamw int buf_sz; 1790da6c28aaSamw int level = 0; 17917f667e74Sjose borrego smb_inaddr_t dns_ip; 1792148c5f43SAlan Wright char *fqdn; 1793148c5f43SAlan Wright char *p; 1794da6c28aaSamw 1795da6c28aaSamw assert(dns_str); 1796da6c28aaSamw assert(*dns_str); 1797da6c28aaSamw 1798da6c28aaSamw if (do_check == DNS_CHECK && del_type != DEL_ALL) { 1799da6c28aaSamw is_exist = dyndns_search_entry(update_zone, hostname, ip_addr, 1800da6c28aaSamw update_type, &timeout, &is_match); 1801da6c28aaSamw 1802da6c28aaSamw if (update_type == UPDATE_ADD && is_exist && is_match) { 1803da6c28aaSamw return (0); 1804da6c28aaSamw } else if (update_type == UPDATE_DEL && !is_exist) { 1805da6c28aaSamw return (0); 1806da6c28aaSamw } 1807da6c28aaSamw } 1808da6c28aaSamw 18097f667e74Sjose borrego if (inet_pton(AF_INET, dns_str, &dns_ip) == 1) 18107f667e74Sjose borrego dns_ip.a_family = AF_INET; 18117f667e74Sjose borrego else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1) 18127f667e74Sjose borrego dns_ip.a_family = AF_INET6; 18137f667e74Sjose borrego 1814da6c28aaSamw retry_higher: 18157f667e74Sjose borrego if ((s = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0) 1816da6c28aaSamw return (-1); 1817da6c28aaSamw 1818da6c28aaSamw id = 0; 1819da6c28aaSamw if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, 1820da6c28aaSamw ip_addr, life_time, update_type, del_type, 0, &id, level)) <= 0) { 1821da6c28aaSamw (void) close(s); 1822da6c28aaSamw return (-1); 1823da6c28aaSamw } 1824da6c28aaSamw 1825da6c28aaSamw if (dyndns_udp_send_recv(s, buf, buf_sz, buf2)) { 1826da6c28aaSamw (void) close(s); 1827da6c28aaSamw return (-1); 1828da6c28aaSamw } 1829da6c28aaSamw 1830da6c28aaSamw (void) close(s); 1831da6c28aaSamw 1832da6c28aaSamw ret = buf2[3] & 0xf; /* error field in UDP */ 1833da6c28aaSamw 1834da6c28aaSamw /* 1835da6c28aaSamw * If it is a NOTAUTH error we should retry with higher domains 1836da6c28aaSamw * until we get a successful reply 1837da6c28aaSamw */ 1838da6c28aaSamw if (ret == NOTAUTH && level++ < MAX_AUTH_RETRIES) 1839da6c28aaSamw goto retry_higher; 1840da6c28aaSamw 1841da6c28aaSamw /* check here for update request is successful */ 1842da6c28aaSamw if (ret == NOERROR) { 1843da6c28aaSamw (void) dyndns_get_nshort(buf2, &rid); 1844da6c28aaSamw if (id != rid) 1845da6c28aaSamw return (-1); 1846da6c28aaSamw return (0); 1847da6c28aaSamw } 1848da6c28aaSamw 1849da6c28aaSamw if (ret == NOTIMP) { 18508d7e4166Sjose borrego dyndns_syslog(LOG_NOTICE, NOTIMP, "dynamic updates"); 1851da6c28aaSamw return (-1); 1852da6c28aaSamw } else if (ret == NOTAUTH) { 18538d7e4166Sjose borrego dyndns_syslog(LOG_NOTICE, NOTAUTH, "DNS"); 1854da6c28aaSamw return (-1); 1855da6c28aaSamw } 1856da6c28aaSamw 1857148c5f43SAlan Wright if ((p = strchr(hostname, '.')) == NULL) 1858148c5f43SAlan Wright return (-1); 1859148c5f43SAlan Wright 1860148c5f43SAlan Wright fqdn = ++p; 1861148c5f43SAlan Wright if (smb_krb5_kt_find(SMB_KRB5_PN_ID_HOST_FQHN, fqdn, 1862148c5f43SAlan Wright SMBNS_KRB5_KEYTAB)) { 1863da6c28aaSamw ret = dyndns_sec_add_remove_entry(update_zone, hostname, 1864da6c28aaSamw ip_addr, life_time, update_type, del_type, dns_str); 1865148c5f43SAlan Wright } else { 1866148c5f43SAlan Wright syslog(LOG_NOTICE, "dyndns: secure update failed: cannot find " 1867148c5f43SAlan Wright "host principal \"%s\" in local keytab file.", hostname); 1868148c5f43SAlan Wright } 1869da6c28aaSamw 1870da6c28aaSamw return (ret); 1871da6c28aaSamw } 1872da6c28aaSamw 1873da6c28aaSamw /* 1874da6c28aaSamw * dyndns_add_entry 1875da6c28aaSamw * Main routine to add an entry into DNS. The attempt will be made on the 1876da6c28aaSamw * the servers returned by smb_get_nameserver(). Upon a successful 1877da6c28aaSamw * attempt on any one of the server, the function will exit with 0. 1878da6c28aaSamw * Otherwise, -1 is retuned to indicate the update attempt on all the 1879da6c28aaSamw * nameservers has failed. 1880da6c28aaSamw * 1881da6c28aaSamw * Parameters: 1882da6c28aaSamw * update_zone: the type of zone to update, use UPDATE_FORW for forward 1883da6c28aaSamw * lookup zone, use UPDATE_REV for reverse lookup zone 1884da6c28aaSamw * hostname : fully qualified hostname 1885da6c28aaSamw * ip_addr : ip address of hostname in string format 1886da6c28aaSamw * life_time : cached time of this entry by others and not within DNS 1887da6c28aaSamw * database 1888da6c28aaSamw * Returns: 1889da6c28aaSamw * -1: error 1890da6c28aaSamw * 0: success 1891da6c28aaSamw */ 1892da6c28aaSamw static int 1893da6c28aaSamw dyndns_add_entry(int update_zone, const char *hostname, const char *ip_addr, 1894da6c28aaSamw int life_time) 1895da6c28aaSamw { 18967f667e74Sjose borrego const char *dns_str; 18978d7e4166Sjose borrego char *which_zone; 18987f667e74Sjose borrego smb_inaddr_t ns_list[MAXNS]; 18997f667e74Sjose borrego char dns_buf[INET6_ADDRSTRLEN]; 1900da6c28aaSamw int i, cnt; 19017f667e74Sjose borrego int rc = 0; 1902da6c28aaSamw 19037f667e74Sjose borrego if (hostname == NULL || ip_addr == NULL) { 1904da6c28aaSamw return (-1); 19057f667e74Sjose borrego } 19067f667e74Sjose borrego cnt = smb_get_nameservers(&ns_list[0], MAXNS); 1907da6c28aaSamw 1908da6c28aaSamw for (i = 0; i < cnt; i++) { 19097f667e74Sjose borrego dns_str = smb_inet_ntop(&ns_list[i], dns_buf, 19107f667e74Sjose borrego SMB_IPSTRLEN(ns_list[i].a_family)); 19117f667e74Sjose borrego if (dns_str == NULL) 1912da6c28aaSamw continue; 1913da6c28aaSamw 19148d7e4166Sjose borrego which_zone = (update_zone == UPDATE_FORW) ? 19158d7e4166Sjose borrego "forward" : "reverse"; 19168d7e4166Sjose borrego syslog(LOG_DEBUG, "dyndns %s lookup zone update %s (%s)", 19178d7e4166Sjose borrego which_zone, hostname, ip_addr); 19188d7e4166Sjose borrego 1919da6c28aaSamw if (dyndns_add_remove_entry(update_zone, hostname, 1920da6c28aaSamw ip_addr, life_time, 19217f667e74Sjose borrego UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_buf) != -1) { 1922da6c28aaSamw rc = 1; 1923da6c28aaSamw break; 1924da6c28aaSamw } 1925da6c28aaSamw } 1926da6c28aaSamw 1927da6c28aaSamw return (rc ? 0 : -1); 1928da6c28aaSamw } 1929da6c28aaSamw 1930da6c28aaSamw /* 1931da6c28aaSamw * dyndns_remove_entry 1932da6c28aaSamw * Main routine to remove an entry or all entries of the same resource name 1933da6c28aaSamw * from DNS. The update attempt will be made on the primary DNS server. If 1934da6c28aaSamw * there is a failure then another attempt will be made on the secondary DNS 1935da6c28aaSamw * server. 1936da6c28aaSamw * Parameters: 1937da6c28aaSamw * update_zone: the type of zone to update, use UPDATE_FORW for forward 1938da6c28aaSamw * lookup zone, use UPDATE_REV for reverse lookup zone 1939da6c28aaSamw * hostname : fully qualified hostname 1940da6c28aaSamw * ip_addr : ip address of hostname in string format 1941da6c28aaSamw * del_type : DEL_ONE for deleting one entry, DEL_ALL for deleting all 1942da6c28aaSamw * entries of the same resource name. Only valid for UPDATE_DEL 1943da6c28aaSamw * Returns: 1944da6c28aaSamw * -1: error 1945da6c28aaSamw * 0: success 1946da6c28aaSamw */ 1947da6c28aaSamw static int 1948da6c28aaSamw dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr, 1949da6c28aaSamw int del_type) 1950da6c28aaSamw { 19517f667e74Sjose borrego const char *dns_str; 19527f667e74Sjose borrego smb_inaddr_t ns_list[MAXNS]; 19537f667e74Sjose borrego char dns_buf[INET6_ADDRSTRLEN]; 1954da6c28aaSamw int i, cnt, scnt; 1955da6c28aaSamw 1956da6c28aaSamw if ((hostname == NULL || ip_addr == NULL)) { 1957da6c28aaSamw return (-1); 1958da6c28aaSamw } 1959da6c28aaSamw cnt = smb_get_nameservers(ns_list, MAXNS); 1960da6c28aaSamw scnt = 0; 1961da6c28aaSamw for (i = 0; i < cnt; i++) { 19627f667e74Sjose borrego dns_str = smb_inet_ntop(&ns_list[i], dns_buf, 19637f667e74Sjose borrego SMB_IPSTRLEN(ns_list[i].a_family)); 19647f667e74Sjose borrego if (dns_str == NULL) 1965da6c28aaSamw continue; 19667f667e74Sjose borrego if (update_zone == UPDATE_FORW) { 1967da6c28aaSamw if (del_type == DEL_ONE) { 19687f667e74Sjose borrego syslog(LOG_DEBUG, "Dynamic update " 19697f667e74Sjose borrego "on forward lookup " 19707f667e74Sjose borrego "zone for %s (%s)...\n", hostname, ip_addr); 1971da6c28aaSamw } else { 19727f667e74Sjose borrego syslog(LOG_DEBUG, "Removing all " 19737f667e74Sjose borrego "entries of %s " 19747f667e74Sjose borrego "in forward lookup zone...\n", hostname); 1975da6c28aaSamw } 19767f667e74Sjose borrego } else { 19777f667e74Sjose borrego if (del_type == DEL_ONE) { 19787f667e74Sjose borrego syslog(LOG_DEBUG, "Dynamic update " 19797f667e74Sjose borrego "on reverse lookup " 19807f667e74Sjose borrego "zone for %s (%s)...\n", hostname, ip_addr); 19817f667e74Sjose borrego } else { 19827f667e74Sjose borrego syslog(LOG_DEBUG, "Removing all " 19837f667e74Sjose borrego "entries of %s " 19847f667e74Sjose borrego "in reverse lookup zone...\n", ip_addr); 19857f667e74Sjose borrego } 19867f667e74Sjose borrego } 1987da6c28aaSamw if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, 0, 19887f667e74Sjose borrego UPDATE_DEL, DNS_NOCHECK, del_type, dns_buf) != -1) { 1989da6c28aaSamw scnt++; 1990da6c28aaSamw break; 1991da6c28aaSamw } 1992da6c28aaSamw } 1993da6c28aaSamw if (scnt) 1994da6c28aaSamw return (0); 1995da6c28aaSamw return (-1); 1996da6c28aaSamw } 1997da6c28aaSamw 1998da6c28aaSamw /* 19998c10a865Sas200622 * dyndns_update_core 2000da6c28aaSamw * Perform dynamic update on both forward and reverse lookup zone using 2001faa1795aSjb150015 * the specified hostname and IP addresses. Before updating DNS, existing 2002faa1795aSjb150015 * host entries with the same hostname in the forward lookup zone are removed 2003da6c28aaSamw * and existing pointer entries with the same IP addresses in the reverse 2004da6c28aaSamw * lookup zone are removed. After DNS update, host entries for current 2005da6c28aaSamw * hostname will show current IP addresses and pointer entries for current 2006da6c28aaSamw * IP addresses will show current hostname. 2007da6c28aaSamw * Parameters: 20089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * fqdn - fully-qualified domain name (in lower case) 20098c10a865Sas200622 * 2010da6c28aaSamw * Returns: 2011da6c28aaSamw * -1: some dynamic DNS updates errors 20126537f381Sas200622 * 0: successful or DDNS disabled. 2013da6c28aaSamw */ 20147f667e74Sjose borrego int 20158c10a865Sas200622 dyndns_update_core(char *fqdn) 2016da6c28aaSamw { 20177b59d02dSjb150015 int forw_update_ok, error; 20187f667e74Sjose borrego char my_ip[INET6_ADDRSTRLEN]; 20197f667e74Sjose borrego const char *my_str; 20207b59d02dSjb150015 smb_niciter_t ni; 2021da6c28aaSamw int rc; 2022faa1795aSjb150015 char fqhn[MAXHOSTNAMELEN]; 2023da6c28aaSamw 20248d7e4166Sjose borrego if (fqdn == NULL || *fqdn == '\0') 20258d7e4166Sjose borrego return (0); 20268d7e4166Sjose borrego 2027dc20a302Sas200622 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 20286537f381Sas200622 return (0); 20299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_gethostname(fqhn, MAXHOSTNAMELEN, SMB_CASE_LOWER) != 0) 2030faa1795aSjb150015 return (-1); 2031faa1795aSjb150015 20329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 20339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * To comply with RFC 4120 section 6.2.1, the fully-qualified hostname 20349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * must be set to lower case. 20359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 2036faa1795aSjb150015 (void) snprintf(fqhn, MAXHOSTNAMELEN, "%s.%s", fqhn, fqdn); 20379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 2038da6c28aaSamw error = 0; 2039da6c28aaSamw forw_update_ok = 0; 2040da6c28aaSamw 2041da6c28aaSamw /* 2042da6c28aaSamw * Dummy IP is okay since we are removing all using the hostname. 2043da6c28aaSamw */ 2044faa1795aSjb150015 if (dyndns_remove_entry(UPDATE_FORW, fqhn, "1.1.1.1", DEL_ALL) == 0) { 2045da6c28aaSamw forw_update_ok = 1; 2046da6c28aaSamw } else { 2047da6c28aaSamw error++; 2048da6c28aaSamw } 2049da6c28aaSamw 20509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_nic_getfirst(&ni) != SMB_NIC_SUCCESS) 20517b59d02dSjb150015 return (-1); 20527b59d02dSjb150015 20537b59d02dSjb150015 do { 2054e11c3f44Smeem if (ni.ni_nic.nic_sysflags & IFF_PRIVATE) 2055da6c28aaSamw continue; 20567f667e74Sjose borrego /* first try ipv4, then ipv6 */ 20577f667e74Sjose borrego my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip, 20587f667e74Sjose borrego SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family)); 20597f667e74Sjose borrego if (my_str == NULL) { 2060da6c28aaSamw error++; 2061da6c28aaSamw continue; 2062da6c28aaSamw } 2063da6c28aaSamw 2064da6c28aaSamw if (forw_update_ok) { 20657f667e74Sjose borrego rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_str, 2066da6c28aaSamw DDNS_TTL); 2067da6c28aaSamw 2068da6c28aaSamw if (rc == -1) 2069da6c28aaSamw error++; 2070da6c28aaSamw } 2071da6c28aaSamw 20727f667e74Sjose borrego rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_str, DEL_ALL); 2073da6c28aaSamw if (rc == 0) { 20747f667e74Sjose borrego rc = dyndns_add_entry(UPDATE_REV, fqhn, my_str, 2075da6c28aaSamw DDNS_TTL); 2076da6c28aaSamw } 2077da6c28aaSamw 2078da6c28aaSamw if (rc == -1) 2079da6c28aaSamw error++; 2080da6c28aaSamw 20819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } while (smb_nic_getnext(&ni) == SMB_NIC_SUCCESS); 2082da6c28aaSamw 2083da6c28aaSamw return ((error == 0) ? 0 : -1); 2084da6c28aaSamw } 2085da6c28aaSamw 2086da6c28aaSamw /* 2087da6c28aaSamw * dyndns_clear_rev_zone 2088da6c28aaSamw * Clear the rev zone records. Must be called to clear the OLD if list 2089da6c28aaSamw * of down records prior to updating the list with new information. 2090da6c28aaSamw * 2091da6c28aaSamw * Parameters: 20929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * fqdn - fully-qualified domain name (in lower case) 2093da6c28aaSamw * Returns: 2094da6c28aaSamw * -1: some dynamic DNS updates errors 20956537f381Sas200622 * 0: successful or DDNS disabled. 2096da6c28aaSamw */ 20977f667e74Sjose borrego int 2098faa1795aSjb150015 dyndns_clear_rev_zone(char *fqdn) 2099da6c28aaSamw { 21007b59d02dSjb150015 int error; 21017f667e74Sjose borrego char my_ip[INET6_ADDRSTRLEN]; 21027b59d02dSjb150015 smb_niciter_t ni; 2103da6c28aaSamw int rc; 2104faa1795aSjb150015 char fqhn[MAXHOSTNAMELEN]; 21057f667e74Sjose borrego const char *my_str; 2106da6c28aaSamw 2107dc20a302Sas200622 if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) 21086537f381Sas200622 return (0); 2109da6c28aaSamw 21109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_gethostname(fqhn, MAXHOSTNAMELEN, SMB_CASE_LOWER) != 0) 2111da6c28aaSamw return (-1); 2112da6c28aaSamw 21139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 21149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * To comply with RFC 4120 section 6.2.1, the fully-qualified hostname 21159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * must be set to lower case. 21169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 2117faa1795aSjb150015 (void) snprintf(fqhn, MAXHOSTNAMELEN, "%s.%s", fqhn, fqdn); 21189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 2119da6c28aaSamw error = 0; 2120da6c28aaSamw 21219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_nic_getfirst(&ni) != SMB_NIC_SUCCESS) 21227b59d02dSjb150015 return (-1); 21237b59d02dSjb150015 21247b59d02dSjb150015 do { 2125e11c3f44Smeem if (ni.ni_nic.nic_sysflags & IFF_PRIVATE) 2126da6c28aaSamw continue; 21277f667e74Sjose borrego my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip, 21287f667e74Sjose borrego SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family)); 21297f667e74Sjose borrego if (my_str == NULL) { 2130da6c28aaSamw error++; 2131da6c28aaSamw continue; 2132da6c28aaSamw } 2133da6c28aaSamw 2134faa1795aSjb150015 rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_ip, DEL_ALL); 2135da6c28aaSamw if (rc != 0) 2136da6c28aaSamw error++; 2137da6c28aaSamw 21389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } while (smb_nic_getnext(&ni) == SMB_NIC_SUCCESS); 2139da6c28aaSamw 2140da6c28aaSamw return ((error == 0) ? 0 : -1); 2141da6c28aaSamw } 2142