ipc_doors.c
1 /******************************************************************************* 2 * 3 * ipc_doors.c 4 * 5 * Description: Implements the Sun doors IPC method. 6 * 7 * Copyright (c) 1997-2000 Messaging Direct Ltd. 8 * All rights reserved. 9 * 10 * Portions Copyright (c) 2003 Jeremy Rumpf 11 * jrumpf@heavyload.net 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY 23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MESSAGING DIRECT LTD. OR 26 * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 32 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 33 * DAMAGE. 34 * 35 * 36 * HISTORY 37 * 38 * 39 * This source file created using 8 space tabs. 40 * 41 ********************************************************************************/ 42 43 44 /**************************************** 45 * enable/disable ifdef 46 *****************************************/ 47 #include "saslauthd-main.h" 48 49 #ifdef USE_DOORS_IPC 50 /****************************************/ 51 52 53 54 /**************************************** 55 * includes 56 *****************************************/ 57 #include <door.h> 58 #include <pthread.h> 59 #include <sys/types.h> 60 #include <sys/stat.h> 61 #include <netinet/in.h> 62 #include <fcntl.h> 63 #include <stdlib.h> 64 #include <stdio.h> 65 #include <errno.h> 66 #include <string.h> 67 #include <unistd.h> 68 #include <stropts.h> 69 70 #include "globals.h" 71 #include "utils.h" 72 73 74 /**************************************** 75 * declarations/protos 76 *****************************************/ 77 static void do_request(void *, char *, size_t, door_desc_t *, uint_t); 78 static void send_no(char *); 79 static void need_thread(door_info_t*); 80 static void *server_thread(void *); 81 82 /**************************************** 83 * module globals 84 *****************************************/ 85 static char *door_file; /* Path to the door file */ 86 static int door_fd; /* Door file descriptor */ 87 static pthread_attr_t thread_attr; /* Thread attributes */ 88 static int num_thr; /* Number of threads */ 89 static pthread_mutex_t num_lock; /* Lock for update */ 90 91 /**************************************** 92 * flags global from saslauthd-main.c 93 * run_path global from saslauthd-main.c 94 * num_procs global from saslauthd-main.c 95 * detach_tty() function from saslauthd-main.c 96 * logger() function from utils.c 97 *****************************************/ 98 99 /************************************************************* 100 * IPC init. Initialize the environment specific to the 101 * Sun doors IPC method. 102 * 103 * __Required Function__ 104 **************************************************************/ 105 void ipc_init() { 106 int rc; 107 size_t door_file_len; 108 109 /************************************************************** 110 * Doors detach immediately, otherwise the process gets confused. 111 * (they don't follow fork() properly) 112 **************************************************************/ 113 detach_tty(); 114 115 /************************************************************** 116 * Setup the door file and the door. 117 **************************************************************/ 118 door_file_len = strlen(run_path) + sizeof(DOOR_FILE) + 1; 119 if (!(door_file = malloc(door_file_len))) { 120 logger(L_ERR, L_FUNC, "could not allocate memory"); 121 exit(1); 122 } 123 124 strlcpy(door_file, run_path, door_file_len); 125 strlcat(door_file, DOOR_FILE, door_file_len); 126 unlink(door_file); 127 128 if ((door_fd = open(door_file, O_CREAT|O_RDWR|O_TRUNC, 0666)) == -1) { 129 rc = errno; 130 logger(L_ERR, L_FUNC, "could not open door file: %s", 131 door_file); 132 logger(L_ERR, L_FUNC, "open: %s", strerror(rc)); 133 exit(1); 134 } 135 136 close(door_fd); 137 138 if ((door_fd = door_create(&do_request, NULL, 0)) < 0) { 139 logger(L_ERR, L_FUNC, "failed to create door"); 140 exit(1); 141 } 142 143 door_server_create(&need_thread); 144 145 if (fattach(door_fd, door_file) < 0) { 146 logger(L_ERR, L_FUNC, "failed to attach door to file: %s", 147 door_file); 148 exit(1); 149 } 150 151 if (chmod(door_file, 0644) < 0) { 152 rc = errno; 153 logger(L_ERR, L_FUNC, "failed to chmod door file: %s", 154 door_file); 155 logger(L_ERR, L_FUNC, "chmod: %s", strerror(rc)); 156 exit(1); 157 } 158 159 logger(L_INFO, L_FUNC, "door on: %s", door_file); 160 161 /************************************************************** 162 * The doors api will handle threads for us, clear the process 163 * model global flag. 164 **************************************************************/ 165 flags &= ~USE_PROCESS_MODEL; 166 167 /* Initialize mutex */ 168 pthread_mutex_init(&num_lock, NULL); 169 170 /* Initialize thread attributes */ 171 pthread_attr_init(&thread_attr); 172 pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM); 173 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); 174 175 return; 176 } 177 178 179 /************************************************************* 180 * Main IPC loop. Sit idle waiting for a door request. All 181 * request get routed to do_request() via the doors api. 182 * 183 * __Required Function__ 184 **************************************************************/ 185 void ipc_loop() { 186 while(1) { 187 pause(); 188 } 189 190 return; 191 } 192 193 194 /************************************************************* 195 * General cleanup. Unlink our files. 196 * 197 * __Required Function__ 198 **************************************************************/ 199 void ipc_cleanup() { 200 unlink(door_file); 201 202 if (flags & VERBOSE) 203 logger(L_DEBUG, L_FUNC, "door file removed: %s", door_file); 204 } 205 206 207 /************************************************************* 208 * Handle the door data, pass the request off to 209 * do_auth() back in saslauthd-main.c, then send the 210 * result back through the door. 211 **************************************************************/ 212 void do_request(void *cookie, char *data, size_t datasize, door_desc_t *dp, size_t ndesc) { 213 unsigned short count = 0; /* input/output data byte count */ 214 char *response = NULL; /* response to send to the client */ 215 char response_buff[1024]; /* temporary response buffer */ 216 char *dataend; /* EOD marker for the door data */ 217 char login[MAX_REQ_LEN + 1]; /* account name to authenticate */ 218 char password[MAX_REQ_LEN + 1]; /* password for authentication */ 219 char service[MAX_REQ_LEN + 1]; /* service name for authentication */ 220 char realm[MAX_REQ_LEN + 1]; /* user realm for authentication */ 221 222 223 /************************************************************** 224 * The input data string consists of the login id, password, 225 * service name and user realm. We'll break them up and then 226 * authenticate them. 227 **************************************************************/ 228 dataend = data + datasize; 229 230 /* login id */ 231 memcpy(&count, data, sizeof(unsigned short)); 232 233 count = ntohs(count); 234 data += sizeof(unsigned short); 235 236 if (count > MAX_REQ_LEN || data + count > dataend) { 237 logger(L_ERR, L_FUNC, "login exceeds MAX_REQ_LEN: %d", 238 MAX_REQ_LEN); 239 send_no(""); 240 return; 241 } 242 243 memcpy(login, data, count); 244 login[count] = '\0'; 245 data += count; 246 247 /* password */ 248 memcpy(&count, data, sizeof(unsigned short)); 249 250 count = ntohs(count); 251 data += sizeof(unsigned short); 252 253 if (count > MAX_REQ_LEN || data + count > dataend) { 254 logger(L_ERR, L_FUNC, "password exceeds MAX_REQ_LEN: %d", 255 MAX_REQ_LEN); 256 send_no(""); 257 return; 258 } 259 260 memcpy(password, data, count); 261 password[count] = '\0'; 262 data += count; 263 264 /* service */ 265 memcpy(&count, data, sizeof(unsigned short)); 266 267 count = ntohs(count); 268 data += sizeof(unsigned short); 269 270 if (count > MAX_REQ_LEN || data + count > dataend) { 271 logger(L_ERR, L_FUNC, "service exceeds MAX_REQ_LEN: %d", 272 MAX_REQ_LEN); 273 send_no(""); 274 return; 275 } 276 277 memcpy(service, data, count); 278 service[count] = '\0'; 279 data += count; 280 281 /* realm */ 282 memcpy(&count, data, sizeof(unsigned short)); 283 284 count = ntohs(count); 285 data += sizeof(unsigned short); 286 287 if (count > MAX_REQ_LEN || data + count > dataend) { 288 logger(L_ERR, L_FUNC, "realm exceeds MAX_REQ_LEN: %d", 289 MAX_REQ_LEN); 290 send_no(""); 291 return; 292 } 293 294 memcpy(realm, data, count); 295 realm[count] = '\0'; 296 297 /************************************************************** 298 * We don't allow NULL passwords or login names 299 **************************************************************/ 300 if (*login == '\0') { 301 logger(L_ERR, L_FUNC, "NULL login received"); 302 send_no("NULL login received"); 303 return; 304 } 305 306 if (*password == '\0') { 307 logger(L_ERR, L_FUNC, "NULL password received"); 308 send_no("NULL password received"); 309 return; 310 } 311 312 /************************************************************** 313 * Get the mechanism response from do_auth() and send it back. 314 **************************************************************/ 315 response = do_auth(login, password, service, realm); 316 317 memset(password, 0, strlen(password)); 318 319 if (response == NULL) { 320 send_no("NULL response from mechanism"); 321 return; 322 } 323 324 strncpy(response_buff, response, 1023); 325 response_buff[1023] = '\0'; 326 free(response); 327 328 if (flags & VERBOSE) 329 logger(L_DEBUG, L_FUNC, "response: %s", response_buff); 330 331 if(door_return(response_buff, strlen(response_buff), NULL, 0) < 0) 332 logger(L_ERR, L_FUNC, "door_return: %s", strerror(errno)); 333 334 return; 335 } 336 337 /************************************************************* 338 * The available server thread pool is depleted. 339 * Create a new thread with suitable attributes. 340 * Client door_call() will block until server thread is available. 341 **************************************************************/ 342 void need_thread(door_info_t *di) { 343 pthread_t newt; 344 int more; 345 346 if (num_procs > 0) { 347 pthread_mutex_lock(&num_lock); 348 more = (num_thr < num_procs); 349 if (more) num_thr++; 350 pthread_mutex_unlock(&num_lock); 351 if (!more) return; 352 } 353 354 pthread_create(&newt, &thread_attr, &server_thread, NULL); 355 } 356 357 /************************************************************* 358 * Start a new server thread. 359 * Make it available for door invocations. 360 **************************************************************/ 361 void *server_thread(void *arg) { 362 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 363 door_return(NULL, 0, NULL, 0); 364 } 365 366 /************************************************************* 367 * In case something went out to lunch while parsing the 368 * request data, we may want to attempt to send back a 369 * "NO" response through the door. The mesg is optional. 370 **************************************************************/ 371 void send_no(char *mesg) { 372 char buff[1024]; 373 374 buff[0] = 'N'; 375 buff[1] = 'O'; 376 buff[2] = ' '; 377 378 /* buff, except for the trailing NUL and 'NO ' */ 379 strncpy(buff + 3, mesg, sizeof(buff) - 1 - 3); 380 buff[1023] = '\0'; 381 382 if (flags & VERBOSE) 383 logger(L_DEBUG, L_FUNC, "response: %s", buff); 384 385 if(door_return(buff, strlen(buff), NULL, 0) < 0) 386 logger(L_ERR, L_FUNC, "door_return: %s", strerror(errno)); 387 388 return; 389 } 390 391 #endif /* USE_DOORS_IPC */