/ cyrus_sasl / saslauthd / ipc_doors.c
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 */