1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2017 Joyent Inc 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * NIS update service 29 */ 30 #include <stdio.h> 31 #include <sys/wait.h> 32 #include <sys/time.h> 33 #include <sys/file.h> 34 #include <ctype.h> 35 #define PORTMAP 36 #include <rpc/rpc.h> 37 #include <rpc/auth_des.h> 38 #include <sys/socket.h> 39 #include <sys/signal.h> 40 #include <sys/stat.h> 41 #include <sys/termio.h> 42 #include <sys/debug.h> 43 #include <strings.h> 44 #include <rpcsvc/ypclnt.h> 45 #include <rpcsvc/yp_prot.h> 46 #include <netdir.h> 47 #include <rpcsvc/ypupd.h> 48 #include <netdb.h> 49 #include "shim.h" 50 #include "yptol.h" 51 52 #define RPC_INETDSOCK 0 /* socket descriptor if using inetd */ 53 #define debug(msg) /* turn off debugging */ 54 55 char YPDIR[] = "/var/yp"; 56 char UPDATEFILE[] = "updaters"; 57 58 void ypupdate_prog(struct svc_req *rqstp, SVCXPRT *transp); 59 void detachfromtty(void); 60 61 static int addr2netname(char *, SVCXPRT *); 62 static int issock(int); 63 64 int insecure; 65 66 int 67 main(int argc, char *argv[]) 68 { 69 char *cmd; 70 int connmaxrec = RPC_MAXDATASIZE; 71 struct stat filestat; 72 73 /* 74 * Check if we are running in N2L mode. If so updated is unsuported. 75 * This could be done by calling is_yptol_mode(), from libnisdb, but it 76 * seems over complex to pull in an entire library for one check so 77 * do it in line. Just pull in the name of file to check. 78 */ 79 if (stat(NTOL_MAP_FILE, &filestat) != -1) { 80 fprintf(stderr, "rpc.updated not supported in NIS to LDAP " 81 "transition mode."); 82 exit(1); 83 } 84 85 86 cmd = argv[0]; 87 switch (argc) { 88 case 0: 89 cmd = "ypupdated"; 90 break; 91 case 1: 92 break; 93 case 2: 94 if (strcmp(argv[1], "-i") == 0) { 95 insecure++; 96 break; 97 } else if (strcmp(argv[1], "-s") == 0) { 98 insecure = 0; 99 break; 100 } 101 /* FALLTHROUGH */ 102 default: 103 fprintf(stderr, "%s: warning -- options ignored\n", cmd); 104 break; 105 } 106 107 if (chdir(YPDIR) < 0) { 108 fprintf(stderr, "%s: can't chdir to ", cmd); 109 perror(YPDIR); 110 exit(1); 111 } 112 113 /* 114 * Set non-blocking mode and maximum record size for 115 * connection oriented RPC transports. 116 */ 117 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) { 118 fprintf(stderr, "unable to set maximum RPC record size"); 119 } 120 121 if (issock(RPC_INETDSOCK)) { 122 SVCXPRT *transp; 123 int proto = 0; 124 transp = svctcp_create(RPC_INETDSOCK, 0, 0); 125 if (transp == NULL) { 126 fprintf(stderr, "%s: cannot create tcp service\n", cmd); 127 exit(1); 128 } 129 if (!svc_register(transp, YPU_PROG, YPU_VERS, ypupdate_prog, 130 proto)) { 131 fprintf(stderr, "%s: couldn't register service\n", cmd); 132 exit(1); 133 } 134 } else { 135 detachfromtty(); 136 (void) rpcb_unset(YPU_PROG, YPU_VERS, 0); 137 if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "tcp")) { 138 fprintf(stderr, "%s: cannot create tcp service\n", cmd); 139 exit(1); 140 } 141 } 142 143 if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "udp")) { 144 fprintf(stderr, "%s: cannot create udp service\n", cmd); 145 exit(1); 146 } 147 148 svc_run(); 149 abort(); 150 /* NOTREACHED */ 151 return (1); 152 } 153 154 /* 155 * Determine if a descriptor belongs to a socket or not 156 */ 157 static int 158 issock(int fd) 159 { 160 struct stat st; 161 162 if (fstat(fd, &st) == -1) 163 return (0); 164 else 165 return (S_ISSOCK(fd)); 166 } 167 168 169 void 170 detachfromtty(void) 171 { 172 int tt; 173 174 close(0); 175 close(1); 176 close(2); 177 switch (fork()) { 178 case -1: 179 perror("fork"); 180 break; 181 case 0: 182 break; 183 default: 184 exit(0); 185 } 186 tt = open("/dev/tty", O_RDWR, 0); 187 if (tt >= 0) { 188 ioctl(tt, TIOCNOTTY, 0); 189 close(tt); 190 } 191 open("/dev/null", O_RDWR, 0); 192 dup(0); 193 dup(0); 194 } 195 196 void 197 ypupdate_prog(struct svc_req *rqstp, SVCXPRT *transp) 198 { 199 struct ypupdate_args args; 200 uint_t rslt; 201 uint_t op; 202 char *netname; 203 char namebuf[MAXNETNAMELEN+1]; 204 struct authunix_parms *aup; 205 206 CTASSERT(sizeof (struct authdes_cred) <= RQCRED_SIZE); 207 CTASSERT(sizeof (struct authunix_parms) <= RQCRED_SIZE); 208 209 switch (rqstp->rq_proc) { 210 case NULLPROC: 211 svc_sendreply(transp, xdr_void, NULL); 212 return; 213 case YPU_CHANGE: 214 op = YPOP_CHANGE; 215 break; 216 case YPU_DELETE: 217 op = YPOP_DELETE; 218 break; 219 case YPU_INSERT: 220 op = YPOP_INSERT; 221 break; 222 case YPU_STORE: 223 op = YPOP_STORE; 224 break; 225 default: 226 svcerr_noproc(transp); 227 return; 228 } 229 230 switch (rqstp->rq_cred.oa_flavor) { 231 case AUTH_DES: 232 netname = ((struct authdes_cred *) 233 rqstp->rq_clntcred)->adc_fullname.name; 234 break; 235 case AUTH_UNIX: 236 if (insecure) { 237 aup = (struct authunix_parms *)rqstp->rq_clntcred; 238 if (aup->aup_uid == 0) { 239 /* 240 * addr2netname(namebuf, svc_getcaller(transp)); 241 */ 242 addr2netname(namebuf, transp); 243 } else { 244 user2netname(namebuf, aup->aup_uid, NULL); 245 } 246 netname = namebuf; 247 break; 248 } 249 /* FALLTHROUGH */ 250 default: 251 svcerr_weakauth(transp); 252 return; 253 } 254 bzero(&args, sizeof (args)); 255 if (!svc_getargs(transp, xdr_ypupdate_args, (caddr_t)&args)) { 256 svcerr_decode(transp); 257 return; 258 } 259 rslt = update(netname, 260 args.mapname, op, args.key.yp_buf_len, args.key.yp_buf_val, 261 args.datum.yp_buf_len, args.datum.yp_buf_val); 262 if (!svc_sendreply(transp, xdr_u_int, (const caddr_t)&rslt)) { 263 debug("svc_sendreply failed"); 264 } 265 if (!svc_freeargs(transp, xdr_ypupdate_args, (caddr_t)&args)) { 266 debug("svc_freeargs failed"); 267 } 268 } 269 270 /* 271 * Determine if requester is allowed to update the given map, 272 * and update it if so. Returns the NIS status, which is zero 273 * if there is no access violation. 274 */ 275 int 276 update(char *requester, char *mapname, uint_t op, uint_t keylen, char *key, 277 uint_t datalen, char *data) 278 { 279 char updater[MAXMAPNAMELEN + 40]; 280 FILE *childargs; 281 FILE *childrslt; 282 int status; 283 int yperrno; 284 int pid; 285 char default_domain[YPMAXDOMAIN]; 286 int err; 287 char fake_key[10]; 288 char *outval = NULL; 289 int outval_len; 290 291 if (getdomainname(default_domain, YPMAXDOMAIN)) { 292 debug("Couldn't get default domain name"); 293 return (YPERR_YPERR); 294 } 295 296 /* check to see if we have a valid mapname */ 297 strncpy(fake_key, "junk", 4); 298 err = yp_match(default_domain, mapname, 299 fake_key, strlen(fake_key), &outval, &outval_len); 300 switch (err) { 301 case 0: 302 case YPERR_KEY: 303 /* do nothing, only worry about above return code */ 304 break; 305 default: 306 /* defensive programming */ 307 return (YPERR_YPERR); 308 break; 309 } 310 311 /* valid map - continue */ 312 sprintf(updater, "make -s -f %s %s", UPDATEFILE, mapname); 313 pid = _openchild(updater, &childargs, &childrslt); 314 if (pid < 0) { 315 debug("openpipes failed"); 316 return (YPERR_YPERR); 317 } 318 319 /* 320 * Write to child 321 */ 322 fprintf(childargs, "%s\n", requester); 323 fprintf(childargs, "%u\n", op); 324 fprintf(childargs, "%u\n", keylen); 325 fwrite(key, keylen, 1, childargs); 326 fprintf(childargs, "\n"); 327 fprintf(childargs, "%u\n", datalen); 328 fwrite(data, datalen, 1, childargs); 329 fprintf(childargs, "\n"); 330 fclose(childargs); 331 332 /* 333 * Read from child 334 */ 335 fscanf(childrslt, "%d", &yperrno); 336 fclose(childrslt); 337 338 wait(&status); 339 if (!WIFEXITED(status)) { 340 return (YPERR_YPERR); 341 } 342 return (yperrno); 343 } 344 345 #if 0 346 addr2netname(char *namebuf, struct sockaddr_in *addr) 347 { 348 struct hostent *h; 349 350 h = gethostbyaddr((const char *) &addr->sin_addr, 351 sizeof (addr->sin_addr), AF_INET); 352 if (h == NULL) { 353 host2netname(namebuf, (const char *) inet_ntoa(addr->sin_addr), 354 NULL); 355 } else { 356 host2netname(namebuf, h->h_name, NULL); 357 } 358 } 359 #endif 360 361 362 static int 363 addr2netname(char *namebuf, SVCXPRT *transp) 364 { 365 struct nd_hostservlist *hostservs = NULL; 366 struct netconfig *nconf; 367 struct netbuf *who; 368 369 who = svc_getrpccaller(transp); 370 if ((who == NULL) || (who->len == 0)) 371 return (-1); 372 if ((nconf = getnetconfigent(transp->xp_netid)) == NULL) 373 return (-1); 374 if (netdir_getbyaddr(nconf, &hostservs, who) != 0) { 375 (void) freenetconfigent(nconf); 376 return (-1); 377 } 378 if (hostservs != NULL) 379 strcpy(namebuf, hostservs->h_hostservs->h_host); 380 381 (void) freenetconfigent(nconf); 382 netdir_free((char *)hostservs, ND_HOSTSERVLIST); 383 return (0); 384 } 385