1 /*******************************************************************************
5 * Description: Implements the Sun doors IPC method.
7 * Copyright (c) 1997-2000 Messaging Direct Ltd.
10 * Portions Copyright (c) 2003 Jeremy Rumpf
11 * jrumpf@heavyload.net
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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.
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
39 * This source file created using 8 space tabs.
41 ********************************************************************************/
44 /****************************************
45 * enable/disable ifdef
46 *****************************************/
47 #include "saslauthd-main.h"
50 /****************************************/
54 /****************************************
56 *****************************************/
59 #include <sys/types.h>
61 #include <netinet/in.h>
74 /****************************************
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 *);
82 /****************************************
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 */
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 *****************************************/
99 /*************************************************************
100 * IPC init. Initialize the environment specific to the
101 * Sun doors IPC method.
103 * __Required Function__
104 **************************************************************/
107 size_t door_file_len;
109 /**************************************************************
110 * Doors detach immediately, otherwise the process gets confused.
111 * (they don't follow fork() properly)
112 **************************************************************/
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");
124 strlcpy(door_file, run_path, door_file_len);
125 strlcat(door_file, DOOR_FILE, door_file_len);
128 if ((door_fd = open(door_file, O_CREAT|O_RDWR|O_TRUNC, 0666)) == -1) {
130 logger(L_ERR, L_FUNC, "could not open door file: %s",
132 logger(L_ERR, L_FUNC, "open: %s", strerror(rc));
138 if ((door_fd = door_create(&do_request, NULL, 0)) < 0) {
139 logger(L_ERR, L_FUNC, "failed to create door");
143 door_server_create(&need_thread);
145 if (fattach(door_fd, door_file) < 0) {
146 logger(L_ERR, L_FUNC, "failed to attach door to file: %s",
151 if (chmod(door_file, 0644) < 0) {
153 logger(L_ERR, L_FUNC, "failed to chmod door file: %s",
155 logger(L_ERR, L_FUNC, "chmod: %s", strerror(rc));
159 logger(L_INFO, L_FUNC, "door on: %s", door_file);
161 /**************************************************************
162 * The doors api will handle threads for us, clear the process
164 **************************************************************/
165 flags &= ~USE_PROCESS_MODEL;
167 /* Initialize mutex */
168 pthread_mutex_init(&num_lock, NULL);
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);
179 /*************************************************************
180 * Main IPC loop. Sit idle waiting for a door request. All
181 * request get routed to do_request() via the doors api.
183 * __Required Function__
184 **************************************************************/
194 /*************************************************************
195 * General cleanup. Unlink our files.
197 * __Required Function__
198 **************************************************************/
203 logger(L_DEBUG, L_FUNC, "door file removed: %s", door_file);
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 */
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
227 **************************************************************/
228 dataend = data + datasize;
231 memcpy(&count, data, sizeof(unsigned short));
233 count = ntohs(count);
234 data += sizeof(unsigned short);
236 if (count > MAX_REQ_LEN || data + count > dataend) {
237 logger(L_ERR, L_FUNC, "login exceeds MAX_REQ_LEN: %d",
243 memcpy(login, data, count);
248 memcpy(&count, data, sizeof(unsigned short));
250 count = ntohs(count);
251 data += sizeof(unsigned short);
253 if (count > MAX_REQ_LEN || data + count > dataend) {
254 logger(L_ERR, L_FUNC, "password exceeds MAX_REQ_LEN: %d",
260 memcpy(password, data, count);
261 password[count] = '\0';
265 memcpy(&count, data, sizeof(unsigned short));
267 count = ntohs(count);
268 data += sizeof(unsigned short);
270 if (count > MAX_REQ_LEN || data + count > dataend) {
271 logger(L_ERR, L_FUNC, "service exceeds MAX_REQ_LEN: %d",
277 memcpy(service, data, count);
278 service[count] = '\0';
282 memcpy(&count, data, sizeof(unsigned short));
284 count = ntohs(count);
285 data += sizeof(unsigned short);
287 if (count > MAX_REQ_LEN || data + count > dataend) {
288 logger(L_ERR, L_FUNC, "realm exceeds MAX_REQ_LEN: %d",
294 memcpy(realm, data, count);
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");
306 if (*password == '\0') {
307 logger(L_ERR, L_FUNC, "NULL password received");
308 send_no("NULL password received");
312 /**************************************************************
313 * Get the mechanism response from do_auth() and send it back.
314 **************************************************************/
315 response = do_auth(login, password, service, realm);
317 memset(password, 0, strlen(password));
319 if (response == NULL) {
320 send_no("NULL response from mechanism");
324 strncpy(response_buff, response, 1023);
325 response_buff[1023] = '\0';
329 logger(L_DEBUG, L_FUNC, "response: %s", response_buff);
331 if(door_return(response_buff, strlen(response_buff), NULL, 0) < 0)
332 logger(L_ERR, L_FUNC, "door_return: %s", strerror(errno));
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) {
347 pthread_mutex_lock(&num_lock);
348 more = (num_thr < num_procs);
350 pthread_mutex_unlock(&num_lock);
354 pthread_create(&newt, &thread_attr, &server_thread, NULL);
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);
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) {
378 /* buff, except for the trailing NUL and 'NO ' */
379 strncpy(buff + 3, mesg, sizeof(buff) - 1 - 3);
383 logger(L_DEBUG, L_FUNC, "response: %s", buff);
385 if(door_return(buff, strlen(buff), NULL, 0) < 0)
386 logger(L_ERR, L_FUNC, "door_return: %s", strerror(errno));
391 #endif /* USE_DOORS_IPC */