1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* LINTLIBRARY */ 23*0Sstevel@tonic-gate 24*0Sstevel@tonic-gate /* 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * nfs security related library routines. 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * Some of the routines in this file are adopted from 33*0Sstevel@tonic-gate * lib/libnsl/netselect/netselect.c and are modified to be 34*0Sstevel@tonic-gate * used for accessing /etc/nfssec.conf. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 38*0Sstevel@tonic-gate /* SVr4.0 1.18 */ 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate #include <stdio.h> 41*0Sstevel@tonic-gate #include <string.h> 42*0Sstevel@tonic-gate #include <ctype.h> 43*0Sstevel@tonic-gate #include <stdlib.h> 44*0Sstevel@tonic-gate #include <syslog.h> 45*0Sstevel@tonic-gate #include <synch.h> 46*0Sstevel@tonic-gate #include <rpc/rpc.h> 47*0Sstevel@tonic-gate #include <nfs/nfs_sec.h> 48*0Sstevel@tonic-gate #include <rpc/rpcsec_gss.h> 49*0Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO 50*0Sstevel@tonic-gate #include "webnfs.h" 51*0Sstevel@tonic-gate #endif 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #define GETBYNAME 1 54*0Sstevel@tonic-gate #define GETBYNUM 2 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * mapping for /etc/nfssec.conf 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate struct sc_data { 60*0Sstevel@tonic-gate char *string; 61*0Sstevel@tonic-gate int value; 62*0Sstevel@tonic-gate }; 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate static struct sc_data sc_service[] = { 65*0Sstevel@tonic-gate "default", rpc_gss_svc_default, 66*0Sstevel@tonic-gate "-", rpc_gss_svc_none, 67*0Sstevel@tonic-gate "none", rpc_gss_svc_none, 68*0Sstevel@tonic-gate "integrity", rpc_gss_svc_integrity, 69*0Sstevel@tonic-gate "privacy", rpc_gss_svc_privacy, 70*0Sstevel@tonic-gate NULL, SC_FAILURE 71*0Sstevel@tonic-gate }; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static char *gettoken(char *, int); 74*0Sstevel@tonic-gate extern int atoi(const char *str); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate extern bool_t rpc_gss_get_principal_name(rpc_gss_principal_t *, char *, 77*0Sstevel@tonic-gate char *, char *, char *); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate extern bool_t rpc_gss_mech_to_oid(char *, rpc_gss_OID *); 80*0Sstevel@tonic-gate extern bool_t rpc_gss_qop_to_num(char *, char *, uint_t *); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * blank() returns true if the line is a blank line, 0 otherwise 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate static int 86*0Sstevel@tonic-gate blank(cp) 87*0Sstevel@tonic-gate char *cp; 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate while (*cp && isspace(*cp)) { 90*0Sstevel@tonic-gate cp++; 91*0Sstevel@tonic-gate } 92*0Sstevel@tonic-gate return (*cp == '\0'); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate /* 96*0Sstevel@tonic-gate * comment() returns true if the line is a comment, 0 otherwise. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate static int 99*0Sstevel@tonic-gate comment(cp) 100*0Sstevel@tonic-gate char *cp; 101*0Sstevel@tonic-gate { 102*0Sstevel@tonic-gate while (*cp && isspace(*cp)) { 103*0Sstevel@tonic-gate cp++; 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate return (*cp == '#'); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* 110*0Sstevel@tonic-gate * getvalue() searches for the given string in the given array, 111*0Sstevel@tonic-gate * and returns the integer value associated with the string. 112*0Sstevel@tonic-gate */ 113*0Sstevel@tonic-gate static unsigned long 114*0Sstevel@tonic-gate getvalue(cp, sc_data) 115*0Sstevel@tonic-gate char *cp; 116*0Sstevel@tonic-gate struct sc_data sc_data[]; 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate int i; /* used to index through the given struct sc_data array */ 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate for (i = 0; sc_data[i].string; i++) { 121*0Sstevel@tonic-gate if (strcmp(sc_data[i].string, cp) == 0) { 122*0Sstevel@tonic-gate break; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate } 125*0Sstevel@tonic-gate return (sc_data[i].value); 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * shift1left() moves all characters in the string over 1 to 130*0Sstevel@tonic-gate * the left. 131*0Sstevel@tonic-gate */ 132*0Sstevel@tonic-gate static void 133*0Sstevel@tonic-gate shift1left(p) 134*0Sstevel@tonic-gate char *p; 135*0Sstevel@tonic-gate { 136*0Sstevel@tonic-gate for (; *p; p++) 137*0Sstevel@tonic-gate *p = *(p + 1); 138*0Sstevel@tonic-gate } 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * gettoken() behaves much like strtok(), except that 143*0Sstevel@tonic-gate * it knows about escaped space characters (i.e., space characters 144*0Sstevel@tonic-gate * preceeded by a '\' are taken literally). 145*0Sstevel@tonic-gate * 146*0Sstevel@tonic-gate * XXX We should make this MT-hot by making it more like strtok_r(). 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate static char * 149*0Sstevel@tonic-gate gettoken(cp, skip) 150*0Sstevel@tonic-gate char *cp; 151*0Sstevel@tonic-gate int skip; 152*0Sstevel@tonic-gate { 153*0Sstevel@tonic-gate static char *savep; /* the place where we left off */ 154*0Sstevel@tonic-gate register char *p; /* the beginning of the new token */ 155*0Sstevel@tonic-gate register char *retp; /* the token to be returned */ 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* Determine if first or subsequent call */ 159*0Sstevel@tonic-gate p = (cp == NULL)? savep: cp; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* Return if no tokens remain. */ 162*0Sstevel@tonic-gate if (p == 0) { 163*0Sstevel@tonic-gate return (NULL); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate while (isspace(*p)) 167*0Sstevel@tonic-gate p++; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if (*p == '\0') { 170*0Sstevel@tonic-gate return (NULL); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Save the location of the token and then skip past it 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate retp = p; 178*0Sstevel@tonic-gate while (*p) { 179*0Sstevel@tonic-gate if (isspace(*p)) 180*0Sstevel@tonic-gate if (skip == TRUE) { 181*0Sstevel@tonic-gate shift1left(p); 182*0Sstevel@tonic-gate continue; 183*0Sstevel@tonic-gate } else 184*0Sstevel@tonic-gate break; 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Only process the escape of the space separator; 187*0Sstevel@tonic-gate * since the token may contain other separators, 188*0Sstevel@tonic-gate * let the other routines handle the escape of 189*0Sstevel@tonic-gate * specific characters in the token. 190*0Sstevel@tonic-gate */ 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate if (*p == '\\' && *(p + 1) != '\n' && isspace(*(p + 1))) { 193*0Sstevel@tonic-gate shift1left(p); 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate p++; 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate if (*p == '\0') { 198*0Sstevel@tonic-gate savep = 0; /* indicate this is last token */ 199*0Sstevel@tonic-gate } else { 200*0Sstevel@tonic-gate *p = '\0'; 201*0Sstevel@tonic-gate savep = ++p; 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate return (retp); 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate /* 207*0Sstevel@tonic-gate * matchname() parses a line of the /etc/nfssec.conf file 208*0Sstevel@tonic-gate * and match the sc_name with the given name. 209*0Sstevel@tonic-gate * If there is a match, it fills the information into the given 210*0Sstevel@tonic-gate * pointer of the seconfig_t structure. 211*0Sstevel@tonic-gate * 212*0Sstevel@tonic-gate * Returns TRUE if a match is found. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate static bool_t 215*0Sstevel@tonic-gate matchname(char *line, char *name, seconfig_t *secp) 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate char *tok1, *tok2; /* holds a token from the line */ 218*0Sstevel@tonic-gate char *secname, *gss_mech, *gss_qop; /* pointer to a secmode name */ 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate if ((secname = gettoken(line, FALSE)) == NULL) { 221*0Sstevel@tonic-gate /* bad line */ 222*0Sstevel@tonic-gate return (FALSE); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (strcmp(secname, name) != 0) { 226*0Sstevel@tonic-gate return (FALSE); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate tok1 = tok2 = NULL; 230*0Sstevel@tonic-gate if (((tok1 = gettoken(NULL, FALSE)) == NULL) || 231*0Sstevel@tonic-gate ((gss_mech = gettoken(NULL, FALSE)) == NULL) || 232*0Sstevel@tonic-gate ((gss_qop = gettoken(NULL, FALSE)) == NULL) || 233*0Sstevel@tonic-gate ((tok2 = gettoken(NULL, FALSE)) == NULL) || 234*0Sstevel@tonic-gate ((secp->sc_service = getvalue(tok2, sc_service)) 235*0Sstevel@tonic-gate == SC_FAILURE)) { 236*0Sstevel@tonic-gate return (FALSE); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate secp->sc_nfsnum = atoi(tok1); 239*0Sstevel@tonic-gate (void) strcpy(secp->sc_name, secname); 240*0Sstevel@tonic-gate (void) strcpy(secp->sc_gss_mech, gss_mech); 241*0Sstevel@tonic-gate secp->sc_gss_mech_type = NULL; 242*0Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') { 243*0Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) || 244*0Sstevel@tonic-gate !rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) { 245*0Sstevel@tonic-gate return (FALSE); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate return (TRUE); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate /* 253*0Sstevel@tonic-gate * matchnum() parses a line of the /etc/nfssec.conf file 254*0Sstevel@tonic-gate * and match the sc_nfsnum with the given number. 255*0Sstevel@tonic-gate * If it is a match, it fills the information in the given pointer 256*0Sstevel@tonic-gate * of the seconfig_t structure. 257*0Sstevel@tonic-gate * 258*0Sstevel@tonic-gate * Returns TRUE if a match is found. 259*0Sstevel@tonic-gate */ 260*0Sstevel@tonic-gate static bool_t 261*0Sstevel@tonic-gate matchnum(char *line, int num, seconfig_t *secp) 262*0Sstevel@tonic-gate { 263*0Sstevel@tonic-gate char *tok1, *tok2; /* holds a token from the line */ 264*0Sstevel@tonic-gate char *secname, *gss_mech, *gss_qop; /* pointer to a secmode name */ 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate if ((secname = gettoken(line, FALSE)) == NULL) { 267*0Sstevel@tonic-gate /* bad line */ 268*0Sstevel@tonic-gate return (FALSE); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate tok1 = tok2 = NULL; 272*0Sstevel@tonic-gate if ((tok1 = gettoken(NULL, FALSE)) == NULL) { 273*0Sstevel@tonic-gate /* bad line */ 274*0Sstevel@tonic-gate return (FALSE); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate if ((secp->sc_nfsnum = atoi(tok1)) != num) { 278*0Sstevel@tonic-gate return (FALSE); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate if (((gss_mech = gettoken(NULL, FALSE)) == NULL) || 282*0Sstevel@tonic-gate ((gss_qop = gettoken(NULL, FALSE)) == NULL) || 283*0Sstevel@tonic-gate ((tok2 = gettoken(NULL, FALSE)) == NULL) || 284*0Sstevel@tonic-gate ((secp->sc_service = getvalue(tok2, sc_service)) 285*0Sstevel@tonic-gate == SC_FAILURE)) { 286*0Sstevel@tonic-gate return (FALSE); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate (void) strcpy(secp->sc_name, secname); 290*0Sstevel@tonic-gate (void) strcpy(secp->sc_gss_mech, gss_mech); 291*0Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') { 292*0Sstevel@tonic-gate if (!rpc_gss_mech_to_oid(gss_mech, &secp->sc_gss_mech_type) || 293*0Sstevel@tonic-gate !rpc_gss_qop_to_num(gss_qop, gss_mech, &secp->sc_qop)) { 294*0Sstevel@tonic-gate return (FALSE); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate return (TRUE); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate /* 302*0Sstevel@tonic-gate * Fill in the RPC Protocol security flavor number 303*0Sstevel@tonic-gate * into the sc_rpcnum of seconfig_t structure. 304*0Sstevel@tonic-gate * 305*0Sstevel@tonic-gate * Mainly to map NFS secmod number to RPCSEC_GSS if 306*0Sstevel@tonic-gate * a mechanism name is specified. 307*0Sstevel@tonic-gate */ 308*0Sstevel@tonic-gate static void 309*0Sstevel@tonic-gate get_rpcnum(seconfig_t *secp) 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate if (secp->sc_gss_mech[0] != '-') { 312*0Sstevel@tonic-gate secp->sc_rpcnum = RPCSEC_GSS; 313*0Sstevel@tonic-gate } else { 314*0Sstevel@tonic-gate secp->sc_rpcnum = secp->sc_nfsnum; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate * Parse a given hostname (nodename[.domain@realm]) to 320*0Sstevel@tonic-gate * instant name (nodename[.domain]) and realm. 321*0Sstevel@tonic-gate * 322*0Sstevel@tonic-gate * Assuming user has allocated the space for inst and realm. 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate static int 325*0Sstevel@tonic-gate parsehostname(char *hostname, char *inst, char *realm) 326*0Sstevel@tonic-gate { 327*0Sstevel@tonic-gate char *h, *r; 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate if (!hostname) 330*0Sstevel@tonic-gate return (0); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate h = (char *)strdup(hostname); 333*0Sstevel@tonic-gate if (!h) { 334*0Sstevel@tonic-gate syslog(LOG_ERR, "parsehostname: no memory\n"); 335*0Sstevel@tonic-gate return (0); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate r = (char *)strchr(h, '@'); 339*0Sstevel@tonic-gate if (!r) { 340*0Sstevel@tonic-gate (void) strcpy(inst, h); 341*0Sstevel@tonic-gate (void) strcpy(realm, ""); 342*0Sstevel@tonic-gate } else { 343*0Sstevel@tonic-gate *r++ = '\0'; 344*0Sstevel@tonic-gate (void) strcpy(inst, h); 345*0Sstevel@tonic-gate (void) strcpy(realm, r); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate free(h); 348*0Sstevel@tonic-gate return (1); 349*0Sstevel@tonic-gate } 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate /* 352*0Sstevel@tonic-gate * Get the name corresponding to a qop num. 353*0Sstevel@tonic-gate */ 354*0Sstevel@tonic-gate char * 355*0Sstevel@tonic-gate nfs_get_qop_name(seconfig_t *entryp) 356*0Sstevel@tonic-gate { 357*0Sstevel@tonic-gate char *tok; /* holds a token from the line */ 358*0Sstevel@tonic-gate char *secname, *gss_qop = NULL; /* pointer to a secmode name */ 359*0Sstevel@tonic-gate static mutex_t matching_lock = DEFAULTMUTEX; 360*0Sstevel@tonic-gate char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */ 361*0Sstevel@tonic-gate FILE *fp; /* file stream for NFSSEC_CONF */ 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) { 364*0Sstevel@tonic-gate return (NULL); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate (void) mutex_lock(&matching_lock); 368*0Sstevel@tonic-gate while (fgets(line, BUFSIZ, fp)) { 369*0Sstevel@tonic-gate if (!(blank(line) || comment(line))) { 370*0Sstevel@tonic-gate if ((secname = gettoken(line, FALSE)) == NULL) { 371*0Sstevel@tonic-gate /* bad line */ 372*0Sstevel@tonic-gate continue; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate if (strcmp(secname, entryp->sc_name) == 0) { 375*0Sstevel@tonic-gate tok = NULL; 376*0Sstevel@tonic-gate if ((tok = gettoken(NULL, FALSE)) == NULL) { 377*0Sstevel@tonic-gate /* bad line */ 378*0Sstevel@tonic-gate goto err; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if (atoi(tok) != entryp->sc_nfsnum) 382*0Sstevel@tonic-gate goto err; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate if ((gettoken(NULL, FALSE) == NULL) || 385*0Sstevel@tonic-gate ((gss_qop = gettoken(NULL, FALSE)) == NULL)) { 386*0Sstevel@tonic-gate goto err; 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate break; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate err: 393*0Sstevel@tonic-gate (void) mutex_unlock(&matching_lock); 394*0Sstevel@tonic-gate (void) fclose(fp); 395*0Sstevel@tonic-gate return (gss_qop); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * This routine creates an auth handle assocaited with the 400*0Sstevel@tonic-gate * negotiated security flavor contained in nfs_sec. The auth 401*0Sstevel@tonic-gate * handle will be used in the next LOOKUP request to fetch 402*0Sstevel@tonic-gate * the filehandle. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate AUTH * 405*0Sstevel@tonic-gate nfs_create_ah(CLIENT *cl, char *hostname, seconfig_t *nfs_sec) 406*0Sstevel@tonic-gate { 407*0Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 408*0Sstevel@tonic-gate char svc_name[MAXNETNAMELEN+1]; 409*0Sstevel@tonic-gate char *gss_qop; 410*0Sstevel@tonic-gate static int window = 60; 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate if (nfs_sec == NULL) 413*0Sstevel@tonic-gate goto err; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate switch (nfs_sec->sc_rpcnum) { 416*0Sstevel@tonic-gate case AUTH_UNIX: 417*0Sstevel@tonic-gate case AUTH_NONE: 418*0Sstevel@tonic-gate return (NULL); 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate case AUTH_DES: 421*0Sstevel@tonic-gate if (!host2netname(netname, hostname, NULL)) 422*0Sstevel@tonic-gate goto err; 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate return (authdes_seccreate(netname, window, hostname, NULL)); 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate case RPCSEC_GSS: 427*0Sstevel@tonic-gate if (cl == NULL) 428*0Sstevel@tonic-gate goto err; 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate if (nfs_sec->sc_gss_mech_type == NULL) { 431*0Sstevel@tonic-gate syslog(LOG_ERR, 432*0Sstevel@tonic-gate "nfs_create_ah: need mechanism information\n"); 433*0Sstevel@tonic-gate goto err; 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* RPCSEC_GSS service names are of the form svc@host.dom */ 437*0Sstevel@tonic-gate (void) sprintf(svc_name, "nfs@%s", hostname); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate gss_qop = nfs_get_qop_name(nfs_sec); 440*0Sstevel@tonic-gate if (gss_qop == NULL) 441*0Sstevel@tonic-gate goto err; 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate return (rpc_gss_seccreate(cl, svc_name, nfs_sec->sc_gss_mech, 444*0Sstevel@tonic-gate nfs_sec->sc_service, gss_qop, NULL, NULL)); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate default: 447*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_create_ah: unknown flavor\n"); 448*0Sstevel@tonic-gate return (NULL); 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate err: 451*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_create_ah: failed to make auth handle\n"); 452*0Sstevel@tonic-gate return (NULL); 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate #ifdef WNFS_SEC_NEGO 456*0Sstevel@tonic-gate /* 457*0Sstevel@tonic-gate * This routine negotiates sec flavors with server and returns: 458*0Sstevel@tonic-gate * SNEGO_SUCCESS: successful; sec flavors are 459*0Sstevel@tonic-gate * returned in snego, 460*0Sstevel@tonic-gate * SNEGO_DEF_VALID: default sec flavor valid; no need 461*0Sstevel@tonic-gate * to negotiate flavors, 462*0Sstevel@tonic-gate * SNEGO_ARRAY_TOO_SMALL: array too small, 463*0Sstevel@tonic-gate * SNEGO_FAILURE: failure 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate /* 466*0Sstevel@tonic-gate * The following depicts how sec flavors are placed in an 467*0Sstevel@tonic-gate * overloaded V2 fhandle: 468*0Sstevel@tonic-gate * 469*0Sstevel@tonic-gate * Note that the first four octets contain the length octet, 470*0Sstevel@tonic-gate * the status octet, and two padded octets to make them XDR 471*0Sstevel@tonic-gate * four-octet aligned. 472*0Sstevel@tonic-gate * 473*0Sstevel@tonic-gate * 1 2 3 4 32 474*0Sstevel@tonic-gate * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 475*0Sstevel@tonic-gate * | l | s | | | sec_1 |...| sec_n |...| | 476*0Sstevel@tonic-gate * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 477*0Sstevel@tonic-gate * 478*0Sstevel@tonic-gate * where 479*0Sstevel@tonic-gate * 480*0Sstevel@tonic-gate * the status octet s indicates whether there are more security 481*0Sstevel@tonic-gate * flavors(1 means yes, 0 means no) that require the client to 482*0Sstevel@tonic-gate * perform another 0x81 LOOKUP to get them, 483*0Sstevel@tonic-gate * 484*0Sstevel@tonic-gate * the length octet l is the length describing the number of 485*0Sstevel@tonic-gate * valid octets that follow. (l = 4 * n, where n is the number 486*0Sstevel@tonic-gate * 487*0Sstevel@tonic-gate * The following depicts how sec flavors are placed in an 488*0Sstevel@tonic-gate * overloaded V3 fhandle: 489*0Sstevel@tonic-gate * 490*0Sstevel@tonic-gate * 1 4 491*0Sstevel@tonic-gate * +--+--+--+--+ 492*0Sstevel@tonic-gate * | len | 493*0Sstevel@tonic-gate * +--+--+--+--+ 494*0Sstevel@tonic-gate * up to 64 495*0Sstevel@tonic-gate * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 496*0Sstevel@tonic-gate * |s | | | | sec_1 | sec_2 | ... | sec_n | 497*0Sstevel@tonic-gate * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 498*0Sstevel@tonic-gate * 499*0Sstevel@tonic-gate * len = 4 * (n+1), where n is the number of security flavors 500*0Sstevel@tonic-gate * sent in the current overloaded filehandle. 501*0Sstevel@tonic-gate * 502*0Sstevel@tonic-gate * the status octet s indicates whether there are more security 503*0Sstevel@tonic-gate * mechanisms(1 means yes, 0 means no) that require the client 504*0Sstevel@tonic-gate * to perform another 0x81 LOOKUP to get them. 505*0Sstevel@tonic-gate * 506*0Sstevel@tonic-gate * Three octets are padded after the status octet. 507*0Sstevel@tonic-gate */ 508*0Sstevel@tonic-gate enum snego_stat 509*0Sstevel@tonic-gate nfs_sec_nego(rpcprog_t vers, CLIENT *clnt, char *fspath, struct snego_t *snego) 510*0Sstevel@tonic-gate { 511*0Sstevel@tonic-gate enum clnt_stat rpc_stat; 512*0Sstevel@tonic-gate static int MAX_V2_CNT = (WNL_FHSIZE/sizeof (int)) - 1; 513*0Sstevel@tonic-gate static int MAX_V3_CNT = (WNL3_FHSIZE/sizeof (int)) - 1; 514*0Sstevel@tonic-gate static struct timeval TIMEOUT = { 25, 0 }; 515*0Sstevel@tonic-gate int status; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate if (clnt == NULL || fspath == NULL || snego == NULL) 518*0Sstevel@tonic-gate return (SNEGO_FAILURE); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate if (vers == WNL_V2) { 521*0Sstevel@tonic-gate wnl_diropargs arg; 522*0Sstevel@tonic-gate wnl_diropres clnt_res; 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 525*0Sstevel@tonic-gate arg.name = fspath; 526*0Sstevel@tonic-gate memset((char *)&clnt_res, 0, sizeof (clnt_res)); 527*0Sstevel@tonic-gate rpc_stat = clnt_call(clnt, WNLPROC_LOOKUP, 528*0Sstevel@tonic-gate (xdrproc_t)xdr_wnl_diropargs, (caddr_t)&arg, 529*0Sstevel@tonic-gate (xdrproc_t)xdr_wnl_diropres, (caddr_t)&clnt_res, 530*0Sstevel@tonic-gate TIMEOUT); 531*0Sstevel@tonic-gate if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL_OK) 532*0Sstevel@tonic-gate return (SNEGO_DEF_VALID); 533*0Sstevel@tonic-gate if (rpc_stat != RPC_AUTHERROR) 534*0Sstevel@tonic-gate return (SNEGO_FAILURE); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate { 537*0Sstevel@tonic-gate struct rpc_err e; 538*0Sstevel@tonic-gate wnl_diropres *res; 539*0Sstevel@tonic-gate char *p; 540*0Sstevel@tonic-gate int tot = 0; 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate CLNT_GETERR(clnt, &e); 543*0Sstevel@tonic-gate if (e.re_why != AUTH_TOOWEAK) 544*0Sstevel@tonic-gate return (SNEGO_FAILURE); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if ((p = malloc(strlen(fspath)+3)) == NULL) { 547*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 548*0Sstevel@tonic-gate return (SNEGO_FAILURE); 549*0Sstevel@tonic-gate } 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Do an x81 LOOKUP 552*0Sstevel@tonic-gate */ 553*0Sstevel@tonic-gate p[0] = (char)WNL_SEC_NEGO; 554*0Sstevel@tonic-gate strcpy(&p[2], fspath); 555*0Sstevel@tonic-gate do { 556*0Sstevel@tonic-gate p[1] = (char)(1+snego->cnt); /* sec index */ 557*0Sstevel@tonic-gate arg.name = p; 558*0Sstevel@tonic-gate res = wnlproc_lookup_2(&arg, clnt); 559*0Sstevel@tonic-gate if (res == NULL || res->status != WNL_OK) { 560*0Sstevel@tonic-gate free(p); 561*0Sstevel@tonic-gate return (SNEGO_FAILURE); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * retrieve flavors from filehandle: 566*0Sstevel@tonic-gate * 1st byte: length 567*0Sstevel@tonic-gate * 2nd byte: status 568*0Sstevel@tonic-gate * 3rd & 4th: pad 569*0Sstevel@tonic-gate * 5th and after: sec flavors. 570*0Sstevel@tonic-gate */ 571*0Sstevel@tonic-gate { 572*0Sstevel@tonic-gate char *c = (char *)&res->wnl_diropres_u. 573*0Sstevel@tonic-gate wnl_diropres.file; 574*0Sstevel@tonic-gate int ii; 575*0Sstevel@tonic-gate int cnt = ((int)*c)/sizeof (uint_t); 576*0Sstevel@tonic-gate /* LINTED pointer alignment */ 577*0Sstevel@tonic-gate int *ip = (int *)(c+sizeof (int)); 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate tot += cnt; 580*0Sstevel@tonic-gate if (tot >= MAX_FLAVORS) { 581*0Sstevel@tonic-gate free(p); 582*0Sstevel@tonic-gate return (SNEGO_ARRAY_TOO_SMALL); 583*0Sstevel@tonic-gate } 584*0Sstevel@tonic-gate status = (int)*(c+1); 585*0Sstevel@tonic-gate if (cnt > MAX_V2_CNT || cnt < 0) { 586*0Sstevel@tonic-gate free(p); 587*0Sstevel@tonic-gate return (SNEGO_FAILURE); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate for (ii = 0; ii < cnt; ii++) 590*0Sstevel@tonic-gate snego->array[snego->cnt+ii] = 591*0Sstevel@tonic-gate ntohl(*(ip+ii)); 592*0Sstevel@tonic-gate snego->cnt += cnt; 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate } while (status); 595*0Sstevel@tonic-gate free(p); 596*0Sstevel@tonic-gate return (SNEGO_SUCCESS); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate } else if (vers == WNL_V3) { 599*0Sstevel@tonic-gate WNL_LOOKUP3args arg; 600*0Sstevel@tonic-gate WNL_LOOKUP3res clnt_res; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 603*0Sstevel@tonic-gate arg.what.name = fspath; 604*0Sstevel@tonic-gate arg.what.dir.data.data_len = 0; 605*0Sstevel@tonic-gate arg.what.dir.data.data_val = 0; 606*0Sstevel@tonic-gate memset((char *)&clnt_res, 0, sizeof (clnt_res)); 607*0Sstevel@tonic-gate rpc_stat = clnt_call(clnt, WNLPROC3_LOOKUP, 608*0Sstevel@tonic-gate (xdrproc_t)xdr_WNL_LOOKUP3args, (caddr_t)&arg, 609*0Sstevel@tonic-gate (xdrproc_t)xdr_WNL_LOOKUP3res, (caddr_t)&clnt_res, 610*0Sstevel@tonic-gate TIMEOUT); 611*0Sstevel@tonic-gate if (rpc_stat == RPC_SUCCESS && clnt_res.status == WNL3_OK) 612*0Sstevel@tonic-gate return (SNEGO_DEF_VALID); 613*0Sstevel@tonic-gate if (rpc_stat != RPC_AUTHERROR) 614*0Sstevel@tonic-gate return (SNEGO_FAILURE); 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate { 617*0Sstevel@tonic-gate struct rpc_err e; 618*0Sstevel@tonic-gate WNL_LOOKUP3res *res; 619*0Sstevel@tonic-gate char *p; 620*0Sstevel@tonic-gate int tot = 0; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate CLNT_GETERR(clnt, &e); 623*0Sstevel@tonic-gate if (e.re_why != AUTH_TOOWEAK) 624*0Sstevel@tonic-gate return (SNEGO_FAILURE); 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate if ((p = malloc(strlen(fspath)+3)) == NULL) { 627*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 628*0Sstevel@tonic-gate return (SNEGO_FAILURE); 629*0Sstevel@tonic-gate } 630*0Sstevel@tonic-gate /* 631*0Sstevel@tonic-gate * Do an x81 LOOKUP 632*0Sstevel@tonic-gate */ 633*0Sstevel@tonic-gate p[0] = (char)WNL_SEC_NEGO; 634*0Sstevel@tonic-gate strcpy(&p[2], fspath); 635*0Sstevel@tonic-gate do { 636*0Sstevel@tonic-gate p[1] = (char)(1+snego->cnt); /* sec index */ 637*0Sstevel@tonic-gate arg.what.name = p; 638*0Sstevel@tonic-gate res = wnlproc3_lookup_3(&arg, clnt); 639*0Sstevel@tonic-gate if (res == NULL || res->status != WNL3_OK) { 640*0Sstevel@tonic-gate free(p); 641*0Sstevel@tonic-gate return (SNEGO_FAILURE); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate /* 645*0Sstevel@tonic-gate * retrieve flavors from filehandle: 646*0Sstevel@tonic-gate * 647*0Sstevel@tonic-gate * 1st byte: status 648*0Sstevel@tonic-gate * 2nd thru 4th: pad 649*0Sstevel@tonic-gate * 5th and after: sec flavors. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate { 652*0Sstevel@tonic-gate char *c = res->WNL_LOOKUP3res_u.res_ok. 653*0Sstevel@tonic-gate object.data.data_val; 654*0Sstevel@tonic-gate int ii; 655*0Sstevel@tonic-gate int len = res->WNL_LOOKUP3res_u.res_ok. 656*0Sstevel@tonic-gate object.data.data_len; 657*0Sstevel@tonic-gate int cnt; 658*0Sstevel@tonic-gate /* LINTED pointer alignment */ 659*0Sstevel@tonic-gate int *ip = (int *)(c+sizeof (int)); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate cnt = len/sizeof (uint_t) - 1; 662*0Sstevel@tonic-gate tot += cnt; 663*0Sstevel@tonic-gate if (tot >= MAX_FLAVORS) { 664*0Sstevel@tonic-gate free(p); 665*0Sstevel@tonic-gate return (SNEGO_ARRAY_TOO_SMALL); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate status = (int)(*c); 668*0Sstevel@tonic-gate if (cnt > MAX_V3_CNT || cnt < 0) { 669*0Sstevel@tonic-gate free(p); 670*0Sstevel@tonic-gate return (SNEGO_FAILURE); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate for (ii = 0; ii < cnt; ii++) 673*0Sstevel@tonic-gate snego->array[snego->cnt+ii] = 674*0Sstevel@tonic-gate ntohl(*(ip+ii)); 675*0Sstevel@tonic-gate snego->cnt += cnt; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate CLNT_FREERES(clnt, xdr_WNL_LOOKUP3res, 678*0Sstevel@tonic-gate (char *)res); 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate } while (status); 681*0Sstevel@tonic-gate free(p); 682*0Sstevel@tonic-gate return (SNEGO_SUCCESS); 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate return (SNEGO_FAILURE); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate #endif 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate /* 690*0Sstevel@tonic-gate * Get seconfig from /etc/nfssec.conf by name or by number or 691*0Sstevel@tonic-gate * by descriptior. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate /* ARGSUSED */ 694*0Sstevel@tonic-gate static int 695*0Sstevel@tonic-gate get_seconfig(int whichway, char *name, int num, 696*0Sstevel@tonic-gate rpc_gss_service_t service, seconfig_t *entryp) 697*0Sstevel@tonic-gate { 698*0Sstevel@tonic-gate static mutex_t matching_lock = DEFAULTMUTEX; 699*0Sstevel@tonic-gate char line[BUFSIZ]; /* holds each line of NFSSEC_CONF */ 700*0Sstevel@tonic-gate FILE *fp; /* file stream for NFSSEC_CONF */ 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate if ((whichway == GETBYNAME) && (name == NULL)) 703*0Sstevel@tonic-gate return (SC_NOTFOUND); 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if ((fp = fopen(NFSSEC_CONF, "r")) == NULL) { 706*0Sstevel@tonic-gate return (SC_OPENFAIL); 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate (void) mutex_lock(&matching_lock); 710*0Sstevel@tonic-gate while (fgets(line, BUFSIZ, fp)) { 711*0Sstevel@tonic-gate if (!(blank(line) || comment(line))) { 712*0Sstevel@tonic-gate switch (whichway) { 713*0Sstevel@tonic-gate case GETBYNAME: 714*0Sstevel@tonic-gate if (matchname(line, name, entryp)) { 715*0Sstevel@tonic-gate goto found; 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate break; 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate case GETBYNUM: 720*0Sstevel@tonic-gate if (matchnum(line, num, entryp)) { 721*0Sstevel@tonic-gate goto found; 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate break; 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate default: 726*0Sstevel@tonic-gate break; 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate (void) mutex_unlock(&matching_lock); 731*0Sstevel@tonic-gate (void) fclose(fp); 732*0Sstevel@tonic-gate return (SC_NOTFOUND); 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate found: 735*0Sstevel@tonic-gate (void) mutex_unlock(&matching_lock); 736*0Sstevel@tonic-gate (void) fclose(fp); 737*0Sstevel@tonic-gate (void) get_rpcnum(entryp); 738*0Sstevel@tonic-gate return (SC_NOERROR); 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate /* 743*0Sstevel@tonic-gate * NFS project private API. 744*0Sstevel@tonic-gate * Get a seconfig entry from /etc/nfssec.conf by nfs specific sec name, 745*0Sstevel@tonic-gate * e.g. des, krb5p, etc. 746*0Sstevel@tonic-gate */ 747*0Sstevel@tonic-gate int 748*0Sstevel@tonic-gate nfs_getseconfig_byname(char *secmode_name, seconfig_t *entryp) 749*0Sstevel@tonic-gate { 750*0Sstevel@tonic-gate if (!entryp) 751*0Sstevel@tonic-gate return (SC_NOMEM); 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate return (get_seconfig(GETBYNAME, secmode_name, 0, rpc_gss_svc_none, 754*0Sstevel@tonic-gate entryp)); 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* 758*0Sstevel@tonic-gate * NFS project private API. 759*0Sstevel@tonic-gate * 760*0Sstevel@tonic-gate * Get a seconfig entry from /etc/nfssec.conf by nfs specific sec number, 761*0Sstevel@tonic-gate * e.g. AUTH_DES, AUTH_KRB5_P, etc. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate int 764*0Sstevel@tonic-gate nfs_getseconfig_bynumber(int nfs_secnum, seconfig_t *entryp) 765*0Sstevel@tonic-gate { 766*0Sstevel@tonic-gate if (!entryp) 767*0Sstevel@tonic-gate return (SC_NOMEM); 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate return (get_seconfig(GETBYNUM, NULL, nfs_secnum, rpc_gss_svc_none, 770*0Sstevel@tonic-gate entryp)); 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate /* 774*0Sstevel@tonic-gate * NFS project private API. 775*0Sstevel@tonic-gate * 776*0Sstevel@tonic-gate * Get a seconfig_t entry used as the default for NFS operations. 777*0Sstevel@tonic-gate * The default flavor entry is defined in /etc/nfssec.conf. 778*0Sstevel@tonic-gate * 779*0Sstevel@tonic-gate * Assume user has allocate spaces for secp. 780*0Sstevel@tonic-gate */ 781*0Sstevel@tonic-gate int 782*0Sstevel@tonic-gate nfs_getseconfig_default(seconfig_t *secp) 783*0Sstevel@tonic-gate { 784*0Sstevel@tonic-gate if (secp == NULL) 785*0Sstevel@tonic-gate return (SC_NOMEM); 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate return (nfs_getseconfig_byname("default", secp)); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * NFS project private API. 793*0Sstevel@tonic-gate * 794*0Sstevel@tonic-gate * Free an sec_data structure. 795*0Sstevel@tonic-gate * Free the parts that nfs_clnt_secdata allocates. 796*0Sstevel@tonic-gate */ 797*0Sstevel@tonic-gate void 798*0Sstevel@tonic-gate nfs_free_secdata(sec_data_t *secdata) 799*0Sstevel@tonic-gate { 800*0Sstevel@tonic-gate dh_k4_clntdata_t *dkdata; 801*0Sstevel@tonic-gate gss_clntdata_t *gdata; 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate if (!secdata) 804*0Sstevel@tonic-gate return; 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate switch (secdata->rpcflavor) { 807*0Sstevel@tonic-gate case AUTH_UNIX: 808*0Sstevel@tonic-gate case AUTH_NONE: 809*0Sstevel@tonic-gate break; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate case AUTH_DES: 812*0Sstevel@tonic-gate /* LINTED pointer alignment */ 813*0Sstevel@tonic-gate dkdata = (dh_k4_clntdata_t *)secdata->data; 814*0Sstevel@tonic-gate if (dkdata) { 815*0Sstevel@tonic-gate if (dkdata->netname) 816*0Sstevel@tonic-gate free(dkdata->netname); 817*0Sstevel@tonic-gate if (dkdata->syncaddr.buf) 818*0Sstevel@tonic-gate free(dkdata->syncaddr.buf); 819*0Sstevel@tonic-gate free(dkdata); 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate break; 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate case RPCSEC_GSS: 824*0Sstevel@tonic-gate /* LINTED pointer alignment */ 825*0Sstevel@tonic-gate gdata = (gss_clntdata_t *)secdata->data; 826*0Sstevel@tonic-gate if (gdata) { 827*0Sstevel@tonic-gate if (gdata->mechanism.elements) 828*0Sstevel@tonic-gate free(gdata->mechanism.elements); 829*0Sstevel@tonic-gate free(gdata); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate break; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate default: 834*0Sstevel@tonic-gate break; 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate free(secdata); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate /* 841*0Sstevel@tonic-gate * Make an client side sec_data structure and fill in appropriate value 842*0Sstevel@tonic-gate * based on its rpc security flavor. 843*0Sstevel@tonic-gate * 844*0Sstevel@tonic-gate * It is caller's responsibility to allocate space for seconfig_t, 845*0Sstevel@tonic-gate * and this routine will allocate space for the sec_data structure 846*0Sstevel@tonic-gate * and related data field. 847*0Sstevel@tonic-gate * 848*0Sstevel@tonic-gate * Return the sec_data_t on success. 849*0Sstevel@tonic-gate * If fail, return NULL pointer. 850*0Sstevel@tonic-gate */ 851*0Sstevel@tonic-gate sec_data_t * 852*0Sstevel@tonic-gate nfs_clnt_secdata(seconfig_t *secp, char *hostname, struct knetconfig *knconf, 853*0Sstevel@tonic-gate struct netbuf *syncaddr, int flags) 854*0Sstevel@tonic-gate { 855*0Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 856*0Sstevel@tonic-gate sec_data_t *secdata; 857*0Sstevel@tonic-gate dh_k4_clntdata_t *dkdata; 858*0Sstevel@tonic-gate gss_clntdata_t *gdata; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate secdata = malloc(sizeof (sec_data_t)); 861*0Sstevel@tonic-gate if (!secdata) { 862*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 863*0Sstevel@tonic-gate return (NULL); 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate (void) memset(secdata, 0, sizeof (sec_data_t)); 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate secdata->secmod = secp->sc_nfsnum; 868*0Sstevel@tonic-gate secdata->rpcflavor = secp->sc_rpcnum; 869*0Sstevel@tonic-gate secdata->uid = secp->sc_uid; 870*0Sstevel@tonic-gate secdata->flags = flags; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 873*0Sstevel@tonic-gate * Now, fill in the information for client side secdata : 874*0Sstevel@tonic-gate * 875*0Sstevel@tonic-gate * For AUTH_UNIX, AUTH_DES 876*0Sstevel@tonic-gate * hostname can be in the form of 877*0Sstevel@tonic-gate * nodename or 878*0Sstevel@tonic-gate * nodename.domain 879*0Sstevel@tonic-gate * 880*0Sstevel@tonic-gate * For RPCSEC_GSS security flavor 881*0Sstevel@tonic-gate * hostname can be in the form of 882*0Sstevel@tonic-gate * nodename or 883*0Sstevel@tonic-gate * nodename.domain or 884*0Sstevel@tonic-gate * nodename@realm (realm can be the same as the domain) or 885*0Sstevel@tonic-gate * nodename.domain@realm 886*0Sstevel@tonic-gate */ 887*0Sstevel@tonic-gate switch (secp->sc_rpcnum) { 888*0Sstevel@tonic-gate case AUTH_UNIX: 889*0Sstevel@tonic-gate case AUTH_NONE: 890*0Sstevel@tonic-gate secdata->data = NULL; 891*0Sstevel@tonic-gate break; 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate case AUTH_DES: 894*0Sstevel@tonic-gate /* 895*0Sstevel@tonic-gate * If hostname is in the format of host.nisdomain 896*0Sstevel@tonic-gate * the netname will be constructed with 897*0Sstevel@tonic-gate * this nisdomain name rather than the default 898*0Sstevel@tonic-gate * domain of the machine. 899*0Sstevel@tonic-gate */ 900*0Sstevel@tonic-gate if (!host2netname(netname, hostname, NULL)) { 901*0Sstevel@tonic-gate syslog(LOG_ERR, "host2netname: %s: unknown\n", 902*0Sstevel@tonic-gate hostname); 903*0Sstevel@tonic-gate goto err_out; 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate dkdata = malloc(sizeof (dh_k4_clntdata_t)); 906*0Sstevel@tonic-gate if (!dkdata) { 907*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 908*0Sstevel@tonic-gate goto err_out; 909*0Sstevel@tonic-gate } 910*0Sstevel@tonic-gate (void) memset((char *)dkdata, 0, sizeof (dh_k4_clntdata_t)); 911*0Sstevel@tonic-gate if ((dkdata->netname = strdup(netname)) == NULL) { 912*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 913*0Sstevel@tonic-gate goto err_out; 914*0Sstevel@tonic-gate } 915*0Sstevel@tonic-gate dkdata->netnamelen = strlen(netname); 916*0Sstevel@tonic-gate dkdata->knconf = knconf; 917*0Sstevel@tonic-gate dkdata->syncaddr = *syncaddr; 918*0Sstevel@tonic-gate dkdata->syncaddr.buf = malloc(syncaddr->len); 919*0Sstevel@tonic-gate if (dkdata->syncaddr.buf == NULL) { 920*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 921*0Sstevel@tonic-gate goto err_out; 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate (void) memcpy(dkdata->syncaddr.buf, syncaddr->buf, 924*0Sstevel@tonic-gate syncaddr->len); 925*0Sstevel@tonic-gate secdata->data = (caddr_t)dkdata; 926*0Sstevel@tonic-gate break; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate case RPCSEC_GSS: { 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate if (secp->sc_gss_mech_type == NULL) { 931*0Sstevel@tonic-gate syslog(LOG_ERR, 932*0Sstevel@tonic-gate "nfs_clnt_secdata: need mechanism information\n"); 933*0Sstevel@tonic-gate goto err_out; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate gdata = malloc(sizeof (gss_clntdata_t)); 937*0Sstevel@tonic-gate if (!gdata) { 938*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 939*0Sstevel@tonic-gate goto err_out; 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate (void) strcpy(gdata->uname, "nfs"); 943*0Sstevel@tonic-gate if (!parsehostname(hostname, gdata->inst, gdata->realm)) { 944*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: bad host name\n"); 945*0Sstevel@tonic-gate goto err_out; 946*0Sstevel@tonic-gate } 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate gdata->mechanism.length = secp->sc_gss_mech_type->length; 949*0Sstevel@tonic-gate if (!(gdata->mechanism.elements = 950*0Sstevel@tonic-gate malloc(secp->sc_gss_mech_type->length))) { 951*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: no memory\n"); 952*0Sstevel@tonic-gate goto err_out; 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate (void) memcpy(gdata->mechanism.elements, 955*0Sstevel@tonic-gate secp->sc_gss_mech_type->elements, 956*0Sstevel@tonic-gate secp->sc_gss_mech_type->length); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate gdata->qop = secp->sc_qop; 959*0Sstevel@tonic-gate gdata->service = secp->sc_service; 960*0Sstevel@tonic-gate secdata->data = (caddr_t)gdata; 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate break; 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate default: 965*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_clnt_secdata: unknown flavor\n"); 966*0Sstevel@tonic-gate goto err_out; 967*0Sstevel@tonic-gate } 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate return (secdata); 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate err_out: 972*0Sstevel@tonic-gate free(secdata); 973*0Sstevel@tonic-gate return (NULL); 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* 977*0Sstevel@tonic-gate * nfs_get_root_principal() maps a host name to its principal name 978*0Sstevel@tonic-gate * based on the given security information. 979*0Sstevel@tonic-gate * 980*0Sstevel@tonic-gate * input : seconfig - security configuration information 981*0Sstevel@tonic-gate * host - the host name which could be in the following forms: 982*0Sstevel@tonic-gate * node 983*0Sstevel@tonic-gate * node.namedomain 984*0Sstevel@tonic-gate * node@secdomain (e.g. kerberos realm is a secdomain) 985*0Sstevel@tonic-gate * node.namedomain@secdomain 986*0Sstevel@tonic-gate * output : rootname_p - address of the principal name for the host 987*0Sstevel@tonic-gate * 988*0Sstevel@tonic-gate * Currently, this routine is only used by share program. 989*0Sstevel@tonic-gate * 990*0Sstevel@tonic-gate */ 991*0Sstevel@tonic-gate bool_t 992*0Sstevel@tonic-gate nfs_get_root_principal(seconfig_t *seconfig, char *host, caddr_t *rootname_p) 993*0Sstevel@tonic-gate { 994*0Sstevel@tonic-gate char netname[MAXNETNAMELEN+1], node[MAX_NAME_LEN]; 995*0Sstevel@tonic-gate char secdomain[MAX_NAME_LEN]; 996*0Sstevel@tonic-gate rpc_gss_principal_t gssname; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate switch (seconfig->sc_rpcnum) { 999*0Sstevel@tonic-gate case AUTH_DES: 1000*0Sstevel@tonic-gate if (!host2netname(netname, host, NULL)) { 1001*0Sstevel@tonic-gate syslog(LOG_ERR, 1002*0Sstevel@tonic-gate "nfs_get_root_principal: unknown host: %s\n", host); 1003*0Sstevel@tonic-gate return (FALSE); 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate *rootname_p = strdup(netname); 1006*0Sstevel@tonic-gate if (!*rootname_p) { 1007*0Sstevel@tonic-gate syslog(LOG_ERR, "nfs_get_root_principal: no memory\n"); 1008*0Sstevel@tonic-gate return (FALSE); 1009*0Sstevel@tonic-gate } 1010*0Sstevel@tonic-gate break; 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate case RPCSEC_GSS: 1013*0Sstevel@tonic-gate if (!parsehostname(host, node, secdomain)) { 1014*0Sstevel@tonic-gate syslog(LOG_ERR, 1015*0Sstevel@tonic-gate "nfs_get_root_principal: bad host name\n"); 1016*0Sstevel@tonic-gate return (FALSE); 1017*0Sstevel@tonic-gate } 1018*0Sstevel@tonic-gate if (!rpc_gss_get_principal_name(&gssname, 1019*0Sstevel@tonic-gate seconfig->sc_gss_mech, "root", 1020*0Sstevel@tonic-gate node, secdomain)) { 1021*0Sstevel@tonic-gate syslog(LOG_ERR, 1022*0Sstevel@tonic-gate "nfs_get_root_principal: can not get principal name : %s\n", host); 1023*0Sstevel@tonic-gate return (FALSE); 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate *rootname_p = (caddr_t)gssname; 1027*0Sstevel@tonic-gate break; 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate default: 1030*0Sstevel@tonic-gate return (FALSE); 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate return (TRUE); 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate /* 1037*0Sstevel@tonic-gate * SYSLOG SC_* errors. 1038*0Sstevel@tonic-gate */ 1039*0Sstevel@tonic-gate int 1040*0Sstevel@tonic-gate nfs_syslog_scerr(int scerror, char msg[]) 1041*0Sstevel@tonic-gate { 1042*0Sstevel@tonic-gate switch (scerror) { 1043*0Sstevel@tonic-gate case SC_NOMEM : 1044*0Sstevel@tonic-gate sprintf(msg, "%s : no memory", NFSSEC_CONF); 1045*0Sstevel@tonic-gate return (0); 1046*0Sstevel@tonic-gate case SC_OPENFAIL : 1047*0Sstevel@tonic-gate sprintf(msg, "can not open %s", NFSSEC_CONF); 1048*0Sstevel@tonic-gate return (0); 1049*0Sstevel@tonic-gate case SC_NOTFOUND : 1050*0Sstevel@tonic-gate sprintf(msg, "has no entry in %s", NFSSEC_CONF); 1051*0Sstevel@tonic-gate return (0); 1052*0Sstevel@tonic-gate case SC_BADENTRIES : 1053*0Sstevel@tonic-gate sprintf(msg, "bad entry in %s", NFSSEC_CONF); 1054*0Sstevel@tonic-gate return (0); 1055*0Sstevel@tonic-gate default: 1056*0Sstevel@tonic-gate msg[0] = '\0'; 1057*0Sstevel@tonic-gate return (-1); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate } 1060