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