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