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