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