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