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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Usermode daemon which is responsible for sending kerberos credentials 28 * expiration warnings to the user, syslog or snmp (eventually), depending 29 * on how it is configured through /etc/krb5/warn.conf. 30 * the code in this file was borrowed from gssd.c 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include <stdio.h> 36 #include <rpc/rpc.h> 37 #include <sys/syslog.h> 38 #include <sys/termios.h> 39 #include <unistd.h> 40 #include <sys/resource.h> 41 #include <sys/utsname.h> 42 #include <sys/systeminfo.h> 43 #include <stdlib.h> 44 #include <stropts.h> 45 #include <fcntl.h> 46 #include <strings.h> 47 #include <syslog.h> 48 #include <thread.h> 49 #include <netdb.h> 50 #include <libgen.h> 51 #include "kwarnd.h" 52 53 #define MAXTHREADS 64 54 55 int kwarnd_debug = 0; /* enable debugging printfs */ 56 57 extern void kwarnprog_1(struct svc_req *, register SVCXPRT *); 58 static void usage(void); 59 static void detachfromtty(void); 60 extern int svc_create_local_service(void (*) (), 61 ulong_t, ulong_t, char *, char *); 62 extern void kwarnd_check_warning_list(void); 63 extern bool_t loadConfigFile(void); 64 65 /* following declarations needed in rpcgen-generated code */ 66 int _rpcpmstart = 0; /* Started by a port monitor ? */ 67 int _rpcfdtype; /* Whether Stream or Datagram ? */ 68 int _rpcsvcdirty; /* Still serving ? */ 69 70 char myhostname[MAXHOSTNAMELEN] = {0}; 71 char progname[MAXNAMELEN] = {0}; 72 73 74 int 75 main(argc, argv) 76 int argc; 77 char **argv; 78 { 79 register SVCXPRT *transp; 80 extern int optind; 81 int c; 82 char mname[FMNAMESZ + 1]; 83 int rpc_svc_mode = RPC_SVC_MT_AUTO; 84 extern int _getuid(); 85 86 87 /* set locale and domain for internationalization */ 88 setlocale(LC_ALL, ""); 89 90 #if !defined(TEXT_DOMAIN) 91 #define TEXT_DOMAIN "SYS_TEST" 92 #endif 93 94 textdomain(TEXT_DOMAIN); 95 96 (void) strlcpy(progname, basename(argv[0]), sizeof (progname)); 97 98 /* 99 * take special note that "_getuid()" is called here. This is necessary 100 * since we must fake out the mechanism libraries calls to getuid() 101 * with a special routine that is provided as part of kwarnd. However, 102 * the call below MUST call the real getuid() to ensure it is running 103 * as root. 104 */ 105 106 #ifdef DEBUG 107 (void) setuid(0); /* DEBUG: set ruid to root */ 108 #endif /* DEBUG */ 109 if (_getuid()) { 110 (void) fprintf(stderr, 111 gettext("[%s] must be run as root\n"), argv[0]); 112 #ifdef DEBUG 113 (void) fprintf(stderr, gettext(" warning only\n")); 114 #else /* !DEBUG */ 115 exit(1); 116 #endif /* DEBUG */ 117 } 118 119 while ((c = getopt(argc, argv, "d")) != -1) 120 switch (c) { 121 case 'd': 122 /* turn on debugging */ 123 kwarnd_debug = 1; 124 break; 125 default: 126 usage(); 127 } 128 129 if (optind != argc) { 130 usage(); 131 } 132 133 (void) gethostname(myhostname, sizeof (myhostname)); 134 135 /* 136 * Started by inetd if name of module just below stream 137 * head is either a sockmod or timod. 138 */ 139 if (!ioctl(0, I_LOOK, mname) && 140 ((strcmp(mname, "sockmod") == 0) || 141 (strcmp(mname, "timod") == 0))) { 142 143 char *netid; 144 struct netconfig *nconf; 145 146 openlog("kwarnd", LOG_PID, LOG_DAEMON); 147 148 if ((netid = getenv("NLSPROVIDER")) == NULL) { 149 netid = "ticotsord"; 150 } 151 152 if ((nconf = getnetconfigent(netid)) == NULL) { 153 syslog(LOG_ERR, gettext("cannot get transport info")); 154 exit(1); 155 } 156 157 if (strcmp(mname, "sockmod") == 0) { 158 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { 159 syslog(LOG_ERR, 160 gettext("could not get the " 161 "right module")); 162 exit(1); 163 } 164 } 165 166 /* XXX - is nconf even needed here? */ 167 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 168 syslog(LOG_ERR, gettext("cannot create server handle")); 169 exit(1); 170 } 171 172 /* 173 * We use a NULL nconf because KWARNPROG has already been 174 * registered with rpcbind. 175 */ 176 if (!svc_reg(transp, KWARNPROG, KWARNVERS, kwarnprog_1, NULL)) { 177 syslog(LOG_ERR, 178 gettext("unable to register " 179 "(KWARNPROG, KWARNVERS)")); 180 exit(1); 181 } 182 183 if (nconf) 184 freenetconfigent(nconf); 185 } else { 186 187 if (!kwarnd_debug) 188 detachfromtty(); 189 190 openlog("kwarnd", LOG_PID, LOG_DAEMON); 191 192 if (svc_create_local_service(kwarnprog_1, KWARNPROG, KWARNVERS, 193 "netpath", "kwarnd") == 0) { 194 syslog(LOG_ERR, gettext("unable to create service")); 195 exit(1); 196 } 197 } 198 199 200 if (kwarnd_debug) { 201 fprintf(stderr, 202 gettext("kwarnd start: \n")); 203 } 204 205 (void) signal(SIGCHLD, SIG_IGN); 206 207 if (thr_create(NULL, 0, 208 (void *(*)(void *))kwarnd_check_warning_list, NULL, 209 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, 210 NULL)) { 211 syslog(LOG_ERR, 212 gettext("unable to create cache_cleanup thread")); 213 exit(1); 214 } 215 216 if (!loadConfigFile()) { 217 syslog(LOG_ERR, gettext("could not read config file\n")); 218 exit(1); 219 } 220 221 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 222 syslog(LOG_ERR, gettext("unable to set automatic MT mode")); 223 exit(1); 224 } 225 226 svc_run(); 227 abort(); 228 /*NOTREACHED*/ 229 #ifdef lint 230 return (1); 231 #endif 232 } 233 234 static void 235 usage(void) 236 { 237 (void) fprintf(stderr, gettext("usage: %s [-d]\n"), progname); 238 exit(1); 239 } 240 241 242 /* 243 * detach from tty 244 */ 245 static void 246 detachfromtty(void) 247 { 248 switch (fork()) { 249 case -1: 250 perror(gettext("kwarnd: can not fork")); 251 exit(1); 252 /*NOTREACHED*/ 253 case 0: 254 break; 255 default: 256 exit(0); 257 } 258 259 /* 260 * Close existing file descriptors, open "/dev/null" as 261 * standard input, output, and error, and detach from 262 * controlling terminal. 263 */ 264 closefrom(0); 265 (void) open("/dev/null", O_RDONLY); 266 (void) open("/dev/null", O_WRONLY); 267 (void) dup(1); 268 (void) setsid(); 269 } 270 271 /*ARGSUSED*/ 272 int 273 kwarnprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res) 274 { 275 xdr_free(xdr_res, res); 276 return (1); 277 } 278