1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Helper routines for nfsmapid and autod daemon 29 * to translate hostname to IP address and Netinfo. 30 */ 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <alloca.h> 34 #include <signal.h> 35 #include <libintl.h> 36 #include <limits.h> 37 #include <errno.h> 38 #include <sys/types.h> 39 #include <string.h> 40 #include <memory.h> 41 #include <pwd.h> 42 #include <grp.h> 43 #include <door.h> 44 #include <syslog.h> 45 #include <fcntl.h> 46 #include <unistd.h> 47 #include <assert.h> 48 #include <deflt.h> 49 #include <netdir.h> 50 #include <nfs/nfs4.h> 51 #include <nfs/nfssys.h> 52 #include <nfs/nfsid_map.h> 53 #include <nfs/mapid.h> 54 #include <nfs/nfs_sec.h> 55 #include <sys/sdt.h> 56 #include <sys/idmap.h> 57 #include <idmap.h> 58 #include <sys/fs/autofs.h> 59 #include "nfs_resolve.h" 60 61 void 62 free_knconf(struct knetconfig *k) 63 { 64 if (k == NULL) 65 return; 66 if (k->knc_protofmly) 67 free(k->knc_protofmly); 68 if (k->knc_proto) 69 free(k->knc_proto); 70 free(k); 71 } 72 73 struct knetconfig * 74 get_knconf(struct netconfig *nconf) 75 { 76 struct stat stbuf; 77 struct knetconfig *k = NULL; 78 int len; 79 80 if (stat(nconf->nc_device, &stbuf) < 0) { 81 syslog(LOG_ERR, "get_knconf: stat %s: %m", nconf->nc_device); 82 return (NULL); 83 } 84 k = (struct knetconfig *)malloc(sizeof (*k)); 85 if (k == NULL) 86 goto nomem; 87 k->knc_semantics = nconf->nc_semantics; 88 89 len = strlen(nconf->nc_protofmly); 90 if (len <= 0) 91 goto err_out; 92 k->knc_protofmly = malloc(KNC_STRSIZE); 93 if (k->knc_protofmly == NULL) 94 goto nomem; 95 bzero(k->knc_protofmly, KNC_STRSIZE); 96 bcopy(nconf->nc_protofmly, k->knc_protofmly, len); 97 98 len = strlen(nconf->nc_proto); 99 if (len <= 0) 100 goto err_out; 101 k->knc_proto = malloc(KNC_STRSIZE); 102 if (k->knc_proto == NULL) 103 goto nomem; 104 bzero(k->knc_proto, KNC_STRSIZE); 105 bcopy(nconf->nc_proto, k->knc_proto, len); 106 107 k->knc_rdev = stbuf.st_rdev; 108 109 return (k); 110 111 nomem: 112 syslog(LOG_ERR, "get_knconf: no memory"); 113 err_out: 114 if (k != NULL) 115 (void) free_knconf(k); 116 return (NULL); 117 } 118 119 /* 120 * Get the information needed for an NFSv4.x referral. This 121 * information includes the netbuf, netname and knconfig. 122 */ 123 struct nfs_fsl_info * 124 get_nfs4ref_info(char *host, int port, int nfsver) 125 { 126 char netname[MAXNETNAMELEN + 1]; 127 enum clnt_stat cstat; 128 struct nfs_fsl_info *fsl_retp = NULL; 129 struct netconfig *netconf = NULL; 130 char *nametemp, *namex = NULL; 131 struct netbuf *nb = NULL; 132 NCONF_HANDLE *nc = NULL; 133 134 fsl_retp = calloc(1, sizeof (struct nfs_fsl_info)); 135 if (fsl_retp == NULL) { 136 syslog(LOG_ERR, "get_nfs4ref_info: no memory\n"); 137 return (NULL); 138 } 139 140 nametemp = malloc(MAXNETNAMELEN + 1); 141 if (nametemp == NULL) { 142 free(fsl_retp); 143 return (NULL); 144 } 145 host2netname(nametemp, host, NULL); 146 namex = calloc(1, strlen(nametemp) + 1); 147 if (namex == NULL) { 148 free(nametemp); 149 free(fsl_retp); 150 return (NULL); 151 } 152 strncpy(namex, nametemp, strlen(nametemp)); 153 free(nametemp); 154 fsl_retp->netname = namex; 155 fsl_retp->netnm_len = strlen(namex) + 1; 156 157 fsl_retp->addr = resolve_netconf(host, NFS_PROGRAM, nfsver, 158 &netconf, port, NULL, NULL, TRUE, NULL, &cstat); 159 160 if (netconf == NULL || fsl_retp->addr == NULL) 161 goto done; 162 163 fsl_retp->knconf = get_knconf(netconf); 164 if (fsl_retp->knconf == NULL) 165 goto done; 166 fsl_retp->knconf_len = (sizeof (struct knetconfig) + 167 (KNC_STRSIZE * 2)); 168 fsl_retp->netbuf_len = (sizeof (struct netbuf) + 169 fsl_retp->addr->maxlen); 170 return (fsl_retp); 171 done: 172 free_nfs4ref_info(fsl_retp); 173 return (NULL); 174 } 175 176 void 177 free_nfs4ref_info(struct nfs_fsl_info *fsl_retp) 178 { 179 if (fsl_retp == NULL) 180 return; 181 free_knconf(fsl_retp->knconf); 182 free(fsl_retp->netname); 183 if (fsl_retp->addr != NULL) { 184 free(fsl_retp->addr->buf); 185 free(fsl_retp->addr); 186 } 187 free(fsl_retp); 188 } 189 190 void 191 cleanup_tli_parms(struct t_bind *tbind, int fd) 192 { 193 if (tbind != NULL) { 194 t_free((char *)tbind, T_BIND); 195 tbind = NULL; 196 } 197 if (fd >= 0) 198 (void) t_close(fd); 199 fd = -1; 200 } 201 202 struct netbuf * 203 resolve_netconf(char *host, rpcprog_t prog, rpcvers_t nfsver, 204 struct netconfig **netconf, ushort_t port, 205 struct t_info *tinfo, caddr_t *fhp, bool_t direct_to_server, 206 char *fspath, enum clnt_stat *cstatp) 207 { 208 NCONF_HANDLE *nc; 209 struct netconfig *nconf = NULL; 210 int nthtry = FIRST_TRY; 211 struct netbuf *nb; 212 enum clnt_stat cstat; 213 214 nc = setnetpath(); 215 if (nc == NULL) 216 goto done; 217 retry: 218 while (nconf = getnetpath(nc)) { 219 if (nconf->nc_flag & NC_VISIBLE) { 220 if (nthtry == FIRST_TRY) { 221 if ((nconf->nc_semantics == 222 NC_TPI_COTS_ORD) || 223 (nconf->nc_semantics == 224 NC_TPI_COTS)) { 225 if (port == 0) 226 break; 227 if ((strcmp(nconf->nc_protofmly, 228 NC_INET) == 0 || 229 strcmp(nconf->nc_protofmly, 230 NC_INET6) == 0) && 231 (strcmp(nconf->nc_proto, 232 NC_TCP) == 0)) 233 break; 234 } 235 } 236 if (nthtry == SECOND_TRY) { 237 if (nconf->nc_semantics == 238 NC_TPI_CLTS) { 239 if (port == 0) 240 break; 241 if ((strcmp(nconf->nc_protofmly, 242 NC_INET) == 0 || 243 strcmp(nconf->nc_protofmly, 244 NC_INET6) == 0) && 245 (strcmp(nconf->nc_proto, 246 NC_UDP) == 0)) 247 break; 248 } 249 } 250 } 251 } /* while */ 252 if (nconf == NULL) { 253 if (++nthtry <= MNT_PREF_LISTLEN) { 254 endnetpath(nc); 255 if ((nc = setnetpath()) == NULL) 256 goto done; 257 goto retry; 258 } else 259 return (NULL); 260 } else { 261 nb = get_server_addr(host, NFS_PROGRAM, nfsver, 262 nconf, port, NULL, NULL, TRUE, NULL, &cstat); 263 if (cstat != RPC_SUCCESS) 264 goto retry; 265 } 266 done: 267 *netconf = nconf; 268 *cstatp = cstat; 269 if (nc) 270 endnetpath(nc); 271 return (nb); 272 } 273 274 int 275 setup_nb_parms(struct netconfig *nconf, struct t_bind *tbind, 276 struct t_info *tinfo, char *hostname, int fd, bool_t direct_to_server, 277 ushort_t port, rpcprog_t prog, rpcvers_t vers, bool_t file_handle) 278 { 279 if (nconf == NULL) { 280 return (-1); 281 } 282 if (direct_to_server == TRUE) { 283 struct nd_hostserv hs; 284 struct nd_addrlist *retaddrs; 285 hs.h_host = hostname; 286 287 if (port == 0) 288 hs.h_serv = "nfs"; 289 else 290 hs.h_serv = NULL; 291 292 if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) { 293 return (-1); 294 } 295 memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 296 retaddrs->n_addrs->len); 297 tbind->addr.len = retaddrs->n_addrs->len; 298 tbind->addr.maxlen = retaddrs->n_addrs->maxlen; 299 netdir_free((void *)retaddrs, ND_ADDRLIST); 300 if (port) { 301 /* LINTED pointer alignment */ 302 if (strcmp(nconf->nc_protofmly, NC_INET) == NULL) 303 ((struct sockaddr_in *) 304 tbind->addr.buf)->sin_port = 305 htons((ushort_t)port); 306 else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL) 307 ((struct sockaddr_in6 *) 308 tbind->addr.buf)->sin6_port = 309 htons((ushort_t)port); 310 } 311 312 if (file_handle) { 313 if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd, 314 NULL) == -1) 315 return (-1); 316 } 317 } else if (!file_handle) { 318 if (port) { 319 /* LINTED pointer alignment */ 320 if (strcmp(nconf->nc_protofmly, NC_INET) == NULL) 321 ((struct sockaddr_in *) 322 tbind->addr.buf)->sin_port = 323 htons((ushort_t)port); 324 else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL) 325 ((struct sockaddr_in6 *) 326 tbind->addr.buf)->sin6_port = 327 htons((ushort_t)port); 328 } 329 } else { 330 return (-1); 331 } 332 return (1); 333 } 334 335 /* 336 * Sets up TLI interface and finds the address withe netdir_getbyname(). 337 * returns the address returned from the call. 338 * Caller frees up the memory allocated here. 339 */ 340 struct netbuf * 341 get_server_addr(char *hostname, rpcprog_t prog, rpcvers_t vers, 342 struct netconfig *nconf, ushort_t port, 343 struct t_info *tinfo, caddr_t *fhp, bool_t direct_to_server, 344 char *fspath, enum clnt_stat *cstat) 345 { 346 int fd = -1; 347 struct t_bind *tbind = NULL; 348 enum clnt_stat cs = RPC_SYSTEMERROR; 349 struct netbuf *nb = NULL; 350 int ret = -1; 351 352 if (prog == NFS_PROGRAM && vers == NFS_V4) 353 if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) 354 goto done; 355 356 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) 357 goto done; 358 359 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) == NULL) 360 goto done; 361 362 if (setup_nb_parms(nconf, tbind, tinfo, hostname, fd, direct_to_server, 363 port, prog, vers, 0) < 0) 364 goto done; 365 366 nb = (struct netbuf *)malloc(sizeof (struct netbuf)); 367 if (nb == NULL) { 368 syslog(LOG_ERR, "no memory\n"); 369 goto done; 370 } 371 nb->buf = (char *)malloc(tbind->addr.maxlen); 372 if (nb->buf == NULL) { 373 syslog(LOG_ERR, "no memory\n"); 374 free(nb); 375 nb = NULL; 376 goto done; 377 } 378 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 379 nb->len = tbind->addr.len; 380 nb->maxlen = tbind->addr.maxlen; 381 cs = RPC_SUCCESS; 382 done: 383 *cstat = cs; 384 cleanup_tli_parms(tbind, fd); 385 return (nb); 386 } 387