1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * warmstart.c 24*7c478bd9Sstevel@tonic-gate * Allows for gathering of registrations from a earlier dumped file. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Copyright 1990,2002-2003 Sun Microsystems, Inc. All rights reserved. 27*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 28*7c478bd9Sstevel@tonic-gate */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <stdio.h> 33*7c478bd9Sstevel@tonic-gate #include <errno.h> 34*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 35*7c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 38*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 39*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 40*7c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h> 41*7c478bd9Sstevel@tonic-gate #endif 42*7c478bd9Sstevel@tonic-gate #include "rpcbind.h" 43*7c478bd9Sstevel@tonic-gate #include <syslog.h> 44*7c478bd9Sstevel@tonic-gate #include <unistd.h> 45*7c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* These files keep the pmap_list and rpcb_list in XDR format */ 48*7c478bd9Sstevel@tonic-gate static const char rpcbfile[] = DAEMON_DIR "/rpcbind.file"; 49*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 50*7c478bd9Sstevel@tonic-gate static const char pmapfile[] = DAEMON_DIR "/portmap.file"; 51*7c478bd9Sstevel@tonic-gate #endif 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static bool_t write_struct(); 55*7c478bd9Sstevel@tonic-gate static bool_t read_struct(); 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate FILE * 58*7c478bd9Sstevel@tonic-gate open_tmp_file(filename) 59*7c478bd9Sstevel@tonic-gate char *filename; 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate int fd; 62*7c478bd9Sstevel@tonic-gate FILE *fp; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Remove any existing files, and create a new one. 66*7c478bd9Sstevel@tonic-gate * Ensure that rpcbind is not forced to overwrite 67*7c478bd9Sstevel@tonic-gate * a file pointed to by a symbolic link created 68*7c478bd9Sstevel@tonic-gate * by an attacker. 69*7c478bd9Sstevel@tonic-gate * Use open O_CREAT|O_EXCL so file is not created 70*7c478bd9Sstevel@tonic-gate * between unlink() and open() operation. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate if (unlink(filename) == -1) { 73*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) 74*7c478bd9Sstevel@tonic-gate return (NULL); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600); 77*7c478bd9Sstevel@tonic-gate if (fd == -1) 78*7c478bd9Sstevel@tonic-gate return (NULL); 79*7c478bd9Sstevel@tonic-gate fp = fdopen(fd, "w"); 80*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 81*7c478bd9Sstevel@tonic-gate close(fd); 82*7c478bd9Sstevel@tonic-gate return (NULL); 83*7c478bd9Sstevel@tonic-gate } 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate return (fp); 86*7c478bd9Sstevel@tonic-gate } 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate static bool_t 89*7c478bd9Sstevel@tonic-gate write_struct(filename, structproc, list) 90*7c478bd9Sstevel@tonic-gate char *filename; 91*7c478bd9Sstevel@tonic-gate xdrproc_t structproc; 92*7c478bd9Sstevel@tonic-gate void *list; 93*7c478bd9Sstevel@tonic-gate { 94*7c478bd9Sstevel@tonic-gate FILE *fp; 95*7c478bd9Sstevel@tonic-gate XDR xdrs; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate fp = open_tmp_file(filename); 98*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 99*7c478bd9Sstevel@tonic-gate int i; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate for (i = 0; i < 10; i++) 102*7c478bd9Sstevel@tonic-gate close(i); 103*7c478bd9Sstevel@tonic-gate fp = open_tmp_file(filename); 104*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 105*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 106*7c478bd9Sstevel@tonic-gate "cannot open file = %s for writing", filename); 107*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "cannot save any registration"); 108*7c478bd9Sstevel@tonic-gate return (FALSE); 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate xdrstdio_create(&xdrs, fp, XDR_ENCODE); 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate if (structproc(&xdrs, list) == FALSE) { 114*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "rpcbind: xdr_%s: failed", filename); 115*7c478bd9Sstevel@tonic-gate fclose(fp); 116*7c478bd9Sstevel@tonic-gate return (FALSE); 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&xdrs); 119*7c478bd9Sstevel@tonic-gate fclose(fp); 120*7c478bd9Sstevel@tonic-gate return (TRUE); 121*7c478bd9Sstevel@tonic-gate } 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate static bool_t 124*7c478bd9Sstevel@tonic-gate read_struct(filename, structproc, list) 125*7c478bd9Sstevel@tonic-gate char *filename; 126*7c478bd9Sstevel@tonic-gate xdrproc_t structproc; 127*7c478bd9Sstevel@tonic-gate void *list; 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate int fd; 130*7c478bd9Sstevel@tonic-gate FILE *fp = NULL; 131*7c478bd9Sstevel@tonic-gate XDR xdrs; 132*7c478bd9Sstevel@tonic-gate struct stat sbuf_fstat, sbuf_lstat; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate fd = open(filename, O_RDONLY, 0600); 135*7c478bd9Sstevel@tonic-gate if (fd == -1) { 136*7c478bd9Sstevel@tonic-gate fprintf(stderr, 137*7c478bd9Sstevel@tonic-gate "rpcbind: cannot open file = %s for reading\n", filename); 138*7c478bd9Sstevel@tonic-gate goto error; 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate fp = fdopen(fd, "r"); 141*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 142*7c478bd9Sstevel@tonic-gate close(fd); 143*7c478bd9Sstevel@tonic-gate fprintf(stderr, 144*7c478bd9Sstevel@tonic-gate "rpcbind: cannot open file = %s for reading\n", filename); 145*7c478bd9Sstevel@tonic-gate goto error; 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate if (fstat(fd, &sbuf_fstat) != 0) { 148*7c478bd9Sstevel@tonic-gate fprintf(stderr, 149*7c478bd9Sstevel@tonic-gate "rpcbind: cannot stat file = %s for reading\n", filename); 150*7c478bd9Sstevel@tonic-gate goto error; 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate if (sbuf_fstat.st_uid != DAEMON_UID || 153*7c478bd9Sstevel@tonic-gate (!S_ISREG(sbuf_fstat.st_mode)) || 154*7c478bd9Sstevel@tonic-gate (sbuf_fstat.st_mode & S_IRWXG) || 155*7c478bd9Sstevel@tonic-gate (sbuf_fstat.st_mode & S_IRWXO) || 156*7c478bd9Sstevel@tonic-gate (sbuf_fstat.st_nlink != 1)) { 157*7c478bd9Sstevel@tonic-gate fprintf(stderr, 158*7c478bd9Sstevel@tonic-gate "rpcbind: invalid permissions on file = %s for reading\n", 159*7c478bd9Sstevel@tonic-gate filename); 160*7c478bd9Sstevel@tonic-gate goto error; 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Make sure that the pathname for fstat and lstat is the same and 164*7c478bd9Sstevel@tonic-gate * that it's not a link. An attacker can create symbolic or 165*7c478bd9Sstevel@tonic-gate * hard links and use them to gain unauthorised access to the 166*7c478bd9Sstevel@tonic-gate * system when rpcbind aborts or terminates on SIGINT or SIGTERM. 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate if (lstat(filename, &sbuf_lstat) != 0) { 169*7c478bd9Sstevel@tonic-gate fprintf(stderr, 170*7c478bd9Sstevel@tonic-gate "rpcbind: cannot lstat file = %s for reading\n", filename); 171*7c478bd9Sstevel@tonic-gate goto error; 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate if (sbuf_lstat.st_uid != DAEMON_UID || 174*7c478bd9Sstevel@tonic-gate (!S_ISREG(sbuf_lstat.st_mode)) || 175*7c478bd9Sstevel@tonic-gate (sbuf_lstat.st_mode & S_IRWXG) || 176*7c478bd9Sstevel@tonic-gate (sbuf_lstat.st_mode & S_IRWXO) || 177*7c478bd9Sstevel@tonic-gate (sbuf_lstat.st_nlink != 1) || 178*7c478bd9Sstevel@tonic-gate (sbuf_fstat.st_dev != sbuf_lstat.st_dev) || 179*7c478bd9Sstevel@tonic-gate (sbuf_fstat.st_ino != sbuf_lstat.st_ino)) { 180*7c478bd9Sstevel@tonic-gate fprintf(stderr, 181*7c478bd9Sstevel@tonic-gate "rpcbind: invalid lstat permissions on file = %s for reading\n", 182*7c478bd9Sstevel@tonic-gate filename); 183*7c478bd9Sstevel@tonic-gate goto error; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate xdrstdio_create(&xdrs, fp, XDR_DECODE); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate if (structproc(&xdrs, list) == FALSE) { 188*7c478bd9Sstevel@tonic-gate fprintf(stderr, "rpcbind: xdr_%s: failed\n", filename); 189*7c478bd9Sstevel@tonic-gate goto error; 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&xdrs); 192*7c478bd9Sstevel@tonic-gate fclose(fp); 193*7c478bd9Sstevel@tonic-gate return (TRUE); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate error: fprintf(stderr, "rpcbind: will start from scratch\n"); 196*7c478bd9Sstevel@tonic-gate if (fp != NULL) 197*7c478bd9Sstevel@tonic-gate fclose(fp); 198*7c478bd9Sstevel@tonic-gate return (FALSE); 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate void 202*7c478bd9Sstevel@tonic-gate write_warmstart(void) 203*7c478bd9Sstevel@tonic-gate { 204*7c478bd9Sstevel@tonic-gate (void) write_struct(rpcbfile, xdr_rpcblist_ptr, &list_rbl); 205*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 206*7c478bd9Sstevel@tonic-gate (void) write_struct(pmapfile, xdr_pmaplist_ptr, &list_pml); 207*7c478bd9Sstevel@tonic-gate #endif 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate void 212*7c478bd9Sstevel@tonic-gate read_warmstart(void) 213*7c478bd9Sstevel@tonic-gate { 214*7c478bd9Sstevel@tonic-gate rpcblist_ptr tmp_rpcbl = NULL; 215*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 216*7c478bd9Sstevel@tonic-gate pmaplist_ptr tmp_pmapl = NULL; 217*7c478bd9Sstevel@tonic-gate #endif 218*7c478bd9Sstevel@tonic-gate int ok1, ok2 = TRUE; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate ok1 = read_struct(rpcbfile, xdr_rpcblist_ptr, &tmp_rpcbl); 221*7c478bd9Sstevel@tonic-gate if (ok1 == FALSE) 222*7c478bd9Sstevel@tonic-gate return; 223*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 224*7c478bd9Sstevel@tonic-gate ok2 = read_struct(pmapfile, xdr_pmaplist_ptr, &tmp_pmapl); 225*7c478bd9Sstevel@tonic-gate #endif 226*7c478bd9Sstevel@tonic-gate if (ok2 == FALSE) { 227*7c478bd9Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&tmp_rpcbl); 228*7c478bd9Sstevel@tonic-gate return; 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&list_rbl); 231*7c478bd9Sstevel@tonic-gate list_rbl = tmp_rpcbl; 232*7c478bd9Sstevel@tonic-gate #ifdef PORTMAP 233*7c478bd9Sstevel@tonic-gate xdr_free((xdrproc_t)xdr_pmaplist_ptr, (char *)&list_pml); 234*7c478bd9Sstevel@tonic-gate list_pml = (pmaplist *)tmp_pmapl; 235*7c478bd9Sstevel@tonic-gate #endif 236*7c478bd9Sstevel@tonic-gate } 237