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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * NIS update service 28 */ 29 #include <stdio.h> 30 #include <sys/wait.h> 31 #include <sys/time.h> 32 #include <sys/file.h> 33 #include <ctype.h> 34 #include <rpc/rpc.h> 35 #include <rpc/auth_des.h> 36 #include <sys/socket.h> 37 #include <sys/signal.h> 38 #include <sys/stat.h> 39 #include <sys/termio.h> 40 #include <strings.h> 41 #include <rpcsvc/ypclnt.h> 42 #include <rpcsvc/yp_prot.h> 43 #include <netdir.h> 44 #include <rpcsvc/ypupd.h> 45 #include <netdb.h> 46 #include "shim.h" 47 #include "yptol.h" 48 49 #define RPC_INETDSOCK 0 /* socket descriptor if using inetd */ 50 #define debug(msg) /* turn off debugging */ 51 52 char YPDIR[] = "/var/yp"; 53 char UPDATEFILE[] = "updaters"; 54 55 void ypupdate_prog(); 56 void detachfromtty(); 57 58 static int addr2netname(char *, SVCXPRT *); 59 static int issock(); 60 61 int insecure; 62 extern SVCXPRT *svctcp_create(int, uint_t, uint_t); 63 extern SVCXPRT *svcudp_create(); 64 65 int 66 main(argc, argv) 67 int argc; 68 char *argv[]; 69 { 70 char *cmd; 71 int connmaxrec = RPC_MAXDATASIZE; 72 struct stat filestat; 73 74 /* 75 * Check if we are running in N2L mode. If so updated is unsuported. 76 * This could be done by calling is_yptol_mode(), from libnisdb, but it 77 * seems over complex to pull in an entire library for one check so 78 * do it in line. Just pull in the name of file to check. 79 */ 80 if (stat(NTOL_MAP_FILE, &filestat) != -1) { 81 fprintf(stderr, "rpc.updated not supported in NIS to LDAP " 82 "transition mode."); 83 exit(1); 84 } 85 86 87 cmd = argv[0]; 88 switch (argc) { 89 case 0: 90 cmd = "ypupdated"; 91 break; 92 case 1: 93 break; 94 case 2: 95 if (strcmp(argv[1], "-i") == 0) { 96 insecure++; 97 break; 98 } else if (strcmp(argv[1], "-s") == 0) { 99 insecure = 0; 100 break; 101 } 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(fd) 159 int fd; 160 { 161 struct stat st; 162 163 if (fstat(fd, &st) == -1) 164 return (0); 165 else 166 return (S_ISSOCK(fd)); 167 } 168 169 170 void 171 detachfromtty() 172 { 173 int tt; 174 175 close(0); 176 close(1); 177 close(2); 178 switch (fork()) { 179 case -1: 180 perror("fork"); 181 break; 182 case 0: 183 break; 184 default: 185 exit(0); 186 } 187 tt = open("/dev/tty", O_RDWR, 0); 188 if (tt >= 0) { 189 ioctl(tt, TIOCNOTTY, 0); 190 close(tt); 191 } 192 open("/dev/null", O_RDWR, 0); 193 dup(0); 194 dup(0); 195 } 196 197 void 198 ypupdate_prog(rqstp, transp) 199 struct svc_req *rqstp; 200 SVCXPRT *transp; 201 { 202 struct ypupdate_args args; 203 uint_t rslt; 204 uint_t op; 205 char *netname; 206 char namebuf[MAXNETNAMELEN+1]; 207 struct authunix_parms *aup; 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 switch (rqstp->rq_cred.oa_flavor) { 230 case AUTH_DES: 231 netname = ((struct authdes_cred *) 232 rqstp->rq_clntcred)->adc_fullname.name; 233 break; 234 case AUTH_UNIX: 235 if (insecure) { 236 aup = (struct authunix_parms *)rqstp->rq_clntcred; 237 if (aup->aup_uid == 0) { 238 /* 239 * addr2netname(namebuf, svc_getcaller(transp)); 240 */ 241 addr2netname(namebuf, transp); 242 } else { 243 user2netname(namebuf, aup->aup_uid, NULL); 244 } 245 netname = namebuf; 246 break; 247 } 248 default: 249 svcerr_weakauth(transp); 250 return; 251 } 252 bzero(&args, sizeof (args)); 253 if (!svc_getargs(transp, xdr_ypupdate_args, (caddr_t)&args)) { 254 svcerr_decode(transp); 255 return; 256 } 257 rslt = update(netname, 258 args.mapname, op, args.key.yp_buf_len, args.key.yp_buf_val, 259 args.datum.yp_buf_len, args.datum.yp_buf_val); 260 if (!svc_sendreply(transp, xdr_u_int, (const caddr_t)&rslt)) { 261 debug("svc_sendreply failed"); 262 } 263 if (!svc_freeargs(transp, xdr_ypupdate_args, (caddr_t)&args)) { 264 debug("svc_freeargs failed"); 265 } 266 } 267 268 /* 269 * Determine if requester is allowed to update the given map, 270 * and update it if so. Returns the NIS status, which is zero 271 * if there is no access violation. 272 */ 273 int 274 update(requester, mapname, op, keylen, key, datalen, data) 275 char *requester; 276 char *mapname; 277 uint_t op; 278 uint_t keylen; 279 char *key; 280 uint_t datalen; 281 char *data; 282 { 283 char updater[MAXMAPNAMELEN + 40]; 284 FILE *childargs; 285 FILE *childrslt; 286 int status; 287 int yperrno; 288 int pid; 289 char default_domain[YPMAXDOMAIN]; 290 int err; 291 char fake_key[10]; 292 char *outval = NULL; 293 int outval_len; 294 295 if (getdomainname(default_domain, YPMAXDOMAIN)) { 296 debug("Couldn't get default domain name"); 297 return (YPERR_YPERR); 298 } 299 300 /* check to see if we have a valid mapname */ 301 strncpy(fake_key, "junk", 4); 302 err = yp_match(default_domain, mapname, 303 fake_key, strlen(fake_key), &outval, &outval_len); 304 switch (err) { 305 case 0: 306 case YPERR_KEY: 307 /* do nothing, only worry about above return code */ 308 break; 309 default: 310 /* defensive programming */ 311 return (YPERR_YPERR); 312 break; 313 } 314 315 /* valid map - continue */ 316 sprintf(updater, "make -s -f %s %s", UPDATEFILE, mapname); 317 pid = _openchild(updater, &childargs, &childrslt); 318 if (pid < 0) { 319 debug("openpipes failed"); 320 return (YPERR_YPERR); 321 } 322 323 /* 324 * Write to child 325 */ 326 fprintf(childargs, "%s\n", requester); 327 fprintf(childargs, "%u\n", op); 328 fprintf(childargs, "%u\n", keylen); 329 fwrite(key, keylen, 1, childargs); 330 fprintf(childargs, "\n"); 331 fprintf(childargs, "%u\n", datalen); 332 fwrite(data, datalen, 1, childargs); 333 fprintf(childargs, "\n"); 334 fclose(childargs); 335 336 /* 337 * Read from child 338 */ 339 fscanf(childrslt, "%d", &yperrno); 340 fclose(childrslt); 341 342 wait(&status); 343 if (!WIFEXITED(status)) { 344 return (YPERR_YPERR); 345 } 346 return (yperrno); 347 } 348 349 #if 0 350 addr2netname(namebuf, addr) 351 char *namebuf; 352 struct sockaddr_in *addr; 353 { 354 struct hostent *h; 355 356 h = gethostbyaddr((const char *) &addr->sin_addr, 357 sizeof (addr->sin_addr), AF_INET); 358 if (h == NULL) { 359 host2netname(namebuf, (const char *) inet_ntoa(addr->sin_addr), 360 NULL); 361 } else { 362 host2netname(namebuf, h->h_name, NULL); 363 } 364 } 365 #endif 366 367 368 static int 369 addr2netname(namebuf, transp) 370 char *namebuf; 371 SVCXPRT *transp; 372 { 373 struct nd_hostservlist *hostservs = NULL; 374 struct netconfig *nconf; 375 struct netbuf *who; 376 377 who = svc_getrpccaller(transp); 378 if ((who == NULL) || (who->len == 0)) 379 return (-1); 380 if ((nconf = getnetconfigent(transp->xp_netid)) 381 == (struct netconfig *)NULL) 382 return (-1); 383 if (netdir_getbyaddr(nconf, &hostservs, who) != 0) { 384 (void) freenetconfigent(nconf); 385 return (-1); 386 } 387 if (hostservs != NULL) 388 strcpy(namebuf, hostservs->h_hostservs->h_host); 389 390 (void) freenetconfigent(nconf); 391 netdir_free((char *)hostservs, ND_HOSTSERVLIST); 392 return (0); 393 } 394