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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * NIS update service 30 */ 31 #include <stdio.h> 32 #include <sys/wait.h> 33 #include <sys/time.h> 34 #include <sys/file.h> 35 #include <ctype.h> 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 <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 62 int insecure; 63 extern SVCXPRT *svctcp_create(int, uint_t, uint_t); 64 extern SVCXPRT *svcudp_create(); 65 66 int 67 main(argc, argv) 68 int argc; 69 char *argv[]; 70 { 71 char *cmd; 72 static int issock(); 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 switch (rqstp->rq_cred.oa_flavor) { 232 case AUTH_DES: 233 netname = ((struct authdes_cred *) 234 rqstp->rq_clntcred)->adc_fullname.name; 235 break; 236 case AUTH_UNIX: 237 if (insecure) { 238 aup = (struct authunix_parms *)rqstp->rq_clntcred; 239 if (aup->aup_uid == 0) { 240 /* 241 * addr2netname(namebuf, svc_getcaller(transp)); 242 */ 243 addr2netname(namebuf, transp); 244 } else { 245 user2netname(namebuf, aup->aup_uid, NULL); 246 } 247 netname = namebuf; 248 break; 249 } 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(requester, mapname, op, keylen, key, datalen, data) 277 char *requester; 278 char *mapname; 279 uint_t op; 280 uint_t keylen; 281 char *key; 282 uint_t datalen; 283 char *data; 284 { 285 char updater[MAXMAPNAMELEN + 40]; 286 FILE *childargs; 287 FILE *childrslt; 288 int status; 289 int yperrno; 290 int pid; 291 char default_domain[YPMAXDOMAIN]; 292 int err; 293 char fake_key[10]; 294 char *outval = NULL; 295 int outval_len; 296 297 if (getdomainname(default_domain, YPMAXDOMAIN)) { 298 debug("Couldn't get default domain name"); 299 return (YPERR_YPERR); 300 } 301 302 /* check to see if we have a valid mapname */ 303 strncpy(fake_key, "junk", 4); 304 err = yp_match(default_domain, mapname, 305 fake_key, strlen(fake_key), &outval, &outval_len); 306 switch (err) { 307 case 0: 308 case YPERR_KEY: 309 /* do nothing, only worry about above return code */ 310 break; 311 default: 312 /* defensive programming */ 313 return (YPERR_YPERR); 314 break; 315 } 316 317 /* valid map - continue */ 318 sprintf(updater, "make -s -f %s %s", UPDATEFILE, mapname); 319 pid = _openchild(updater, &childargs, &childrslt); 320 if (pid < 0) { 321 debug("openpipes failed"); 322 return (YPERR_YPERR); 323 } 324 325 /* 326 * Write to child 327 */ 328 fprintf(childargs, "%s\n", requester); 329 fprintf(childargs, "%u\n", op); 330 fprintf(childargs, "%u\n", keylen); 331 fwrite(key, keylen, 1, childargs); 332 fprintf(childargs, "\n"); 333 fprintf(childargs, "%u\n", datalen); 334 fwrite(data, datalen, 1, childargs); 335 fprintf(childargs, "\n"); 336 fclose(childargs); 337 338 /* 339 * Read from child 340 */ 341 fscanf(childrslt, "%d", &yperrno); 342 fclose(childrslt); 343 344 wait(&status); 345 if (!WIFEXITED(status)) { 346 return (YPERR_YPERR); 347 } 348 return (yperrno); 349 } 350 351 #if 0 352 addr2netname(namebuf, addr) 353 char *namebuf; 354 struct sockaddr_in *addr; 355 { 356 struct hostent *h; 357 358 h = gethostbyaddr((const char *) &addr->sin_addr, 359 sizeof (addr->sin_addr), AF_INET); 360 if (h == NULL) { 361 host2netname(namebuf, (const char *) inet_ntoa(addr->sin_addr), 362 NULL); 363 } else { 364 host2netname(namebuf, h->h_name, NULL); 365 } 366 } 367 #endif 368 369 370 static int 371 addr2netname(namebuf, transp) 372 char *namebuf; 373 SVCXPRT *transp; 374 { 375 struct nd_hostservlist *hostservs = NULL; 376 struct netconfig *nconf; 377 struct netbuf *who; 378 379 who = svc_getrpccaller(transp); 380 if ((who == NULL) || (who->len == 0)) 381 return (-1); 382 if ((nconf = getnetconfigent(transp->xp_netid)) 383 == (struct netconfig *)NULL) 384 return (-1); 385 if (netdir_getbyaddr(nconf, &hostservs, who) != 0) { 386 (void) freenetconfigent(nconf); 387 return (-1); 388 } 389 if (hostservs != NULL) 390 strcpy(namebuf, hostservs->h_hostservs->h_host); 391 392 (void) freenetconfigent(nconf); 393 netdir_free((char *)hostservs, ND_HOSTSERVLIST); 394 return (0); 395 } 396