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