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 #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 85 /* set locale and domain for internationalization */ 86 setlocale(LC_ALL, ""); 87 88 #if !defined(TEXT_DOMAIN) 89 #define TEXT_DOMAIN "SYS_TEST" 90 #endif 91 92 textdomain(TEXT_DOMAIN); 93 94 (void) strlcpy(progname, basename(argv[0]), sizeof (progname)); 95 96 /* 97 * Take special note that "getuid()" is called here. This call is used 98 * rather that app_krb5_user_uid(), to ensure ktkt_warnd(1M) is running 99 * as root. 100 */ 101 #ifdef DEBUG 102 (void) setuid(0); /* DEBUG: set ruid to root */ 103 #endif /* DEBUG */ 104 if (getuid()) { 105 (void) fprintf(stderr, 106 gettext("[%s] must be run as root\n"), argv[0]); 107 #ifdef DEBUG 108 (void) fprintf(stderr, gettext(" warning only\n")); 109 #else /* !DEBUG */ 110 exit(1); 111 #endif /* DEBUG */ 112 } 113 114 while ((c = getopt(argc, argv, "d")) != -1) 115 switch (c) { 116 case 'd': 117 /* turn on debugging */ 118 kwarnd_debug = 1; 119 break; 120 default: 121 usage(); 122 } 123 124 if (optind != argc) { 125 usage(); 126 } 127 128 (void) gethostname(myhostname, sizeof (myhostname)); 129 130 /* 131 * Started by inetd if name of module just below stream 132 * head is either a sockmod or timod. 133 */ 134 if (!ioctl(0, I_LOOK, mname) && 135 ((strcmp(mname, "sockmod") == 0) || 136 (strcmp(mname, "timod") == 0))) { 137 138 char *netid; 139 struct netconfig *nconf; 140 141 openlog("kwarnd", LOG_PID, LOG_DAEMON); 142 143 if ((netid = getenv("NLSPROVIDER")) == NULL) { 144 netid = "ticotsord"; 145 } 146 147 if ((nconf = getnetconfigent(netid)) == NULL) { 148 syslog(LOG_ERR, gettext("cannot get transport info")); 149 exit(1); 150 } 151 152 if (strcmp(mname, "sockmod") == 0) { 153 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { 154 syslog(LOG_ERR, 155 gettext("could not get the " 156 "right module")); 157 exit(1); 158 } 159 } 160 161 /* XXX - is nconf even needed here? */ 162 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 163 syslog(LOG_ERR, gettext("cannot create server handle")); 164 exit(1); 165 } 166 167 /* 168 * We use a NULL nconf because KWARNPROG has already been 169 * registered with rpcbind. 170 */ 171 if (!svc_reg(transp, KWARNPROG, KWARNVERS, kwarnprog_1, NULL)) { 172 syslog(LOG_ERR, 173 gettext("unable to register " 174 "(KWARNPROG, KWARNVERS)")); 175 exit(1); 176 } 177 178 if (nconf) 179 freenetconfigent(nconf); 180 } else { 181 182 if (!kwarnd_debug) 183 detachfromtty(); 184 185 openlog("kwarnd", LOG_PID, LOG_DAEMON); 186 187 if (svc_create_local_service(kwarnprog_1, KWARNPROG, KWARNVERS, 188 "netpath", "kwarnd") == 0) { 189 syslog(LOG_ERR, gettext("unable to create service")); 190 exit(1); 191 } 192 } 193 194 195 if (kwarnd_debug) { 196 fprintf(stderr, 197 gettext("kwarnd start: \n")); 198 } 199 200 (void) signal(SIGCHLD, SIG_IGN); 201 202 if (thr_create(NULL, 0, 203 (void *(*)(void *))kwarnd_check_warning_list, NULL, 204 THR_DETACHED | THR_DAEMON | THR_NEW_LWP, 205 NULL)) { 206 syslog(LOG_ERR, 207 gettext("unable to create cache_cleanup thread")); 208 exit(1); 209 } 210 211 if (!loadConfigFile()) { 212 syslog(LOG_ERR, gettext("could not read config file\n")); 213 exit(1); 214 } 215 216 if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) { 217 syslog(LOG_ERR, gettext("unable to set automatic MT mode")); 218 exit(1); 219 } 220 221 svc_run(); 222 abort(); 223 /*NOTREACHED*/ 224 #ifdef lint 225 return (1); 226 #endif 227 } 228 229 static void 230 usage(void) 231 { 232 (void) fprintf(stderr, gettext("usage: %s [-d]\n"), progname); 233 exit(1); 234 } 235 236 237 /* 238 * detach from tty 239 */ 240 static void 241 detachfromtty(void) 242 { 243 switch (fork()) { 244 case -1: 245 perror(gettext("kwarnd: can not fork")); 246 exit(1); 247 /*NOTREACHED*/ 248 case 0: 249 break; 250 default: 251 exit(0); 252 } 253 254 /* 255 * Close existing file descriptors, open "/dev/null" as 256 * standard input, output, and error, and detach from 257 * controlling terminal. 258 */ 259 closefrom(0); 260 (void) open("/dev/null", O_RDONLY); 261 (void) open("/dev/null", O_WRONLY); 262 (void) dup(1); 263 (void) setsid(); 264 } 265 266 /*ARGSUSED*/ 267 int 268 kwarnprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res) 269 { 270 xdr_free(xdr_res, res); 271 return (1); 272 } 273