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 2017 Joyent Inc
  24  * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * Portions of this source code were derived from Berkeley 4.3 BSD
  33  * under license from the Regents of the University of California.
  34  */
  35 
  36 /*
  37  * YP update service
  38  */
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #include <sys/types.h>
  42 #include <sys/file.h>
  43 #include <sys/signal.h>
  44 #include <sys/wait.h>
  45 #include <rpc/rpc.h>
  46 #include <rpc/nettype.h>
  47 #include <rpcsvc/ypupd.h>
  48 #include <rpcsvc/ypclnt.h>
  49 #include <sys/debug.h>
  50 #include <netdir.h>
  51 #include <stropts.h>
  52 #ifdef SYSLOG
  53 #include <syslog.h>
  54 #else
  55 #define LOG_ERR 1
  56 #define openlog(a, b, c)
  57 #endif
  58 
  59 #ifdef DEBUG
  60 #define RPC_SVC_FG
  61 #define debug(msg)      fprintf(stderr, "%s\n", msg);
  62 #else
  63 #define debug(msg)      /* turn off debugging */
  64 #endif
  65 
  66 static char YPDIR[] = "/var/yp";
  67 static char UPDATEFILE[] = "/var/yp/updaters";
  68 #define _RPCSVC_CLOSEDOWN 120
  69 
  70 static int addr2netname();
  71 static void closedown();
  72 static void ypupdate_prog();
  73 static void msgout();
  74 static int update();
  75 static int insecure;
  76 static int _rpcpmstart;         /* Started by a port monitor ? */
  77 static int _rpcsvcdirty;        /* Still serving ? */
  78 
  79 extern unsigned int alarm();
  80 extern void exit();
  81 extern int close();
  82 extern long fork();
  83 extern int free();
  84 extern struct netconfig *getnetconfigent();
  85 extern int strcmp();
  86 extern int strcpy();
  87 extern int syslog();
  88 extern void *signal();
  89 extern int setsid();
  90 extern int t_getinfo();
  91 extern int user2netname();
  92 extern int _openchild();
  93 
  94 main(argc, argv)
  95         int argc;
  96         char *argv[];
  97 {
  98         pid_t   pid;
  99         char *cmd;
 100         char mname[FMNAMESZ + 1];
 101 
 102         if (geteuid() != 0) {
 103                 (void) fprintf(stderr, "must be root to run %s\n", argv[0]);
 104                 exit(1);
 105         }
 106 
 107         cmd = argv[0];
 108         switch (argc) {
 109         case 0:
 110                 cmd = "ypupdated";
 111                 break;
 112         case 1:
 113                 break;
 114         case 2:
 115                 if (strcmp(argv[1], "-i") == 0) {
 116                         insecure++;
 117                         break;
 118                 }
 119         default:
 120                 fprintf(stderr, "%s: warning -- options ignored\n", cmd);
 121                 break;
 122         }
 123 
 124         if (chdir(YPDIR) < 0) {
 125                 fprintf(stderr, "%s: can't chdir to ", cmd);
 126                 perror(YPDIR);
 127                 exit(1);
 128         }
 129 
 130         if (!ioctl(0, I_LOOK, mname) &&
 131                 (strcmp(mname, "sockmod") == 0 ||
 132                                 strcmp(mname, "timod") == 0)) {
 133                 /*
 134                  * Started from port monitor: use 0 as fd
 135                  */
 136                 char *netid;
 137                 struct netconfig *nconf = NULL;
 138                 SVCXPRT *transp;
 139                 int pmclose;
 140                 extern char *getenv();
 141 
 142                 _rpcpmstart = 1;
 143                 if ((netid = getenv("NLSPROVIDER")) == NULL) {
 144                         msgout("cannot get transport name");
 145                 }
 146                 if ((nconf = getnetconfigent(netid)) == NULL) {
 147                         msgout("cannot get transport info");
 148                 }
 149                 if (strcmp(mname, "sockmod") == 0) {
 150                         if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) {
 151                                 msgout("could not get the right module");
 152                                 exit(1);
 153                         }
 154                 }
 155                 pmclose = (t_getstate(0) != T_DATAXFER);
 156                 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
 157                         msgout("cannot create update server handle");
 158                         exit(1);
 159                 }
 160                 if (!svc_reg(transp, YPU_PROG, YPU_VERS, ypupdate_prog, 0)) {
 161                         msgout("unable to register (YPBINDPROG, YPBINDVERS).");
 162                         exit(1);
 163                 }
 164                 if (nconf)
 165                         freenetconfigent(nconf);
 166 
 167                 if (pmclose) {
 168                         (void) signal(SIGALRM, closedown);
 169                         (void) alarm(_RPCSVC_CLOSEDOWN);
 170                 }
 171                 svc_run();
 172                 exit(1);
 173         }
 174 #ifndef RPC_SVC_FG
 175         /*
 176          * Started from shell; background thyself and run
 177          */
 178         pid = fork();
 179 
 180         if (pid < 0) {
 181                 perror("cannot fork");
 182                 exit(1);
 183         }
 184         if (pid)
 185                 exit(0);
 186         closefrom(0);
 187         (void) setsid();
 188         openlog("ypupdated", LOG_PID, LOG_DAEMON);
 189 #endif
 190         if (!svc_create(ypupdate_prog, YPU_PROG, YPU_VERS, "netpath")) {
 191                 msgout("unable to create (YPU_PROG, YPU_VERS) for netpath.");
 192                 exit(1);
 193         }
 194 
 195         svc_run();
 196         msgout("svc_run returned");
 197         exit(1);
 198         /* NOTREACHED */
 199 }
 200 
 201 static void
 202 ypupdate_prog(rqstp, transp)
 203         struct svc_req *rqstp;
 204         SVCXPRT *transp;
 205 {
 206         struct ypupdate_args args;
 207         uint_t rslt;
 208         uint_t op;
 209         char *netname;
 210         char namebuf[MAXNETNAMELEN+1];
 211         struct authunix_parms *aup;
 212 
 213         switch (rqstp->rq_proc) {
 214         case NULLPROC:
 215                 svc_sendreply(transp, xdr_void, NULL);
 216                 return;
 217         case YPU_CHANGE:
 218                 op = YPOP_CHANGE;
 219                 break;
 220         case YPU_DELETE:
 221                 op = YPOP_DELETE;
 222                 break;
 223         case YPU_INSERT:
 224                 op = YPOP_INSERT;
 225                 break;
 226         case YPU_STORE:
 227                 op = YPOP_STORE;
 228                 break;
 229         default:
 230                 svcerr_noproc(transp);
 231                 return;
 232         }
 233 #ifdef DEBUG
 234         fprintf(stderr, "ypupdated: request received\n");
 235 #endif
 236         switch (rqstp->rq_cred.oa_flavor) {
 237         case AUTH_DES:
 238                 CTASSERT(sizeof (struct authdes_cred) <= RQCRED_SIZE);
 239                 netname = ((struct authdes_cred *)
 240                         rqstp->rq_clntcred)->adc_fullname.name;
 241                 break;
 242         case AUTH_UNIX:
 243                 if (insecure) {
 244                         CTASSERT(sizeof (struct authunix_parms) <= RQCRED_SIZE);
 245                         aup = (struct authunix_parms *)rqstp->rq_clntcred;
 246                         if (aup->aup_uid == 0) {
 247                                 if (addr2netname(namebuf, transp) != 0) {
 248                                         fprintf(stderr,
 249                                                 "addr2netname failing for %d\n",
 250                                                 aup->aup_uid);
 251                                         svcerr_systemerr(transp);
 252                                         return;
 253                                 }
 254                         } else {
 255                                 if (user2netname(namebuf, aup->aup_uid, NULL)
 256                                     != 0) {
 257                                         fprintf(stderr,
 258                                                 "user2netname failing for %d\n",
 259                                                 aup->aup_uid);
 260                                         svcerr_systemerr(transp);
 261                                         return;
 262                                 }
 263                         }
 264                         netname = namebuf;
 265                         break;
 266                 }
 267         default:
 268                 svcerr_weakauth(transp);
 269                 return;
 270         }
 271         memset(&args, 0, sizeof (args));
 272         if (!svc_getargs(transp, xdr_ypupdate_args, (char *)&args)) {
 273                 svcerr_decode(transp);
 274                 return;
 275         }
 276 #ifdef DEBUG
 277         fprintf(stderr, "netname = %s\n, map=%s\n key=%s\n",
 278                 netname, args.mapname, args.key.yp_buf_val);
 279 #endif
 280         rslt = update(netname, args.mapname, op,
 281                 args.key.yp_buf_len, args.key.yp_buf_val,
 282                 args.datum.yp_buf_len, args.datum.yp_buf_val);
 283         if (!svc_sendreply(transp, xdr_u_int, (char *)&rslt)) {
 284                 debug("svc_sendreply failed");
 285         }
 286         if (!svc_freeargs(transp, xdr_ypupdate_args, (char *)&args)) {
 287                 debug("svc_freeargs failed");
 288         }
 289 }
 290 
 291 /*
 292  * Determine if requester is allowed to update the given map,
 293  * and update it if so. Returns the yp status, which is zero
 294  * if there is no access violation.
 295  */
 296 static
 297 update(requester, mapname, op, keylen, key, datalen, data)
 298         char *requester;
 299         char *mapname;
 300         uint_t op;
 301         uint_t keylen;
 302         char *key;
 303         uint_t datalen;
 304         char *data;
 305 {
 306         char updater[MAXMAPNAMELEN + 40];
 307         FILE *childargs;
 308         FILE *childrslt;
 309         int status;
 310         int yperrno = 0;
 311         int pid;
 312 
 313         sprintf(updater, "/usr/ccs/bin/make -s -f %s %s", UPDATEFILE, mapname);
 314 #ifdef DEBUG
 315         fprintf(stderr, "updater: %s\n", updater);
 316         fprintf(stderr, "requestor = %s, op = %d, key = %s\n",
 317                 requester, op, key);
 318         fprintf(stderr, "data = %s\n", data);
 319 #endif
 320         pid = _openchild(updater, &childargs, &childrslt);
 321         if (pid < 0) {
 322                 debug("openpipes failed");
 323                 return (YPERR_YPERR);
 324         }
 325 
 326         /*
 327          * Write to child
 328          */
 329         fprintf(childargs, "%s\n", requester);
 330         fprintf(childargs, "%u\n", op);
 331         fprintf(childargs, "%u\n", keylen);
 332         fwrite(key, keylen, 1, childargs);
 333         fprintf(childargs, "\n");
 334         fprintf(childargs, "%u\n", datalen);
 335         fwrite(data, datalen, 1, childargs);
 336         fprintf(childargs, "\n");
 337         fclose(childargs);
 338 
 339         /*
 340          * Read from child
 341          */
 342         fscanf(childrslt, "%d", &yperrno);
 343         fclose(childrslt);
 344 
 345         wait(&status);
 346         if (!WIFEXITED(status)) {
 347                 return (YPERR_YPERR);
 348         }
 349         return (yperrno);
 350 }
 351 
 352 static void
 353 msgout(msg)
 354         char *msg;
 355 {
 356         if (_rpcpmstart)
 357                 syslog(LOG_ERR, msg);
 358         else
 359                 (void) fprintf(stderr, "%s\n", msg);
 360 }
 361 
 362 void
 363 closedown()
 364 {
 365         if (_rpcsvcdirty == 0) {
 366                 int i, openfd;
 367                 struct t_info tinfo;
 368 
 369                 if (t_getinfo(0, tinfo) || (tinfo.servtype == T_CLTS))
 370                         exit(0);
 371 
 372                 for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++)
 373                         if (svc_pollfd[i].fd >= 0)
 374                                 openfd++;
 375 
 376                 if (openfd <= 1)
 377                         exit(0);
 378         }
 379         (void) alarm(_RPCSVC_CLOSEDOWN);
 380 }
 381 
 382 static int
 383 addr2netname(namebuf, transp)
 384         char *namebuf;
 385         SVCXPRT *transp;
 386 {
 387         struct nd_hostservlist *hostservs = NULL;
 388         struct netconfig *nconf;
 389         struct netbuf *who;
 390 
 391         who = svc_getrpccaller(transp);
 392         if ((who == NULL) || (who->len == 0))
 393                 return (-1);
 394         if ((nconf = getnetconfigent(transp->xp_netid))
 395                 == (struct netconfig *)NULL)
 396                 return (-1);
 397         if (netdir_getbyaddr(nconf, &hostservs, who) != 0) {
 398                 (void) freenetconfigent(nconf);
 399                 return (-1);
 400         }
 401         if (hostservs == NULL) {
 402                 msgout("ypupdated: netdir_getbyaddr failed\n");
 403         } else {
 404                 strcpy(namebuf, hostservs->h_hostservs->h_host);
 405         }
 406         (void) freenetconfigent(nconf);
 407         netdir_free((char *)hostservs, ND_HOSTSERVLIST);
 408         return (0);
 409 }