Home | History | Annotate | Download | only in libnisdb
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <syslog.h>
     31 #include <sys/types.h>
     32 #include <sys/stat.h>
     33 #include <errno.h>
     34 #include <malloc.h>
     35 #include <strings.h>
     36 #include "nis_servlist.h"
     37 #include "nisdb_rw.h"
     38 
     39 #ifdef	MEM_DEBUG
     40 #define	XFREE		xfree
     41 #define	XMALLOC		xmalloc
     42 #define	XCALLOC		xcalloc
     43 #define	XSTRDUP		xstrdup
     44 #ifdef	__STDC__
     45 extern void xfree(void *);
     46 extern char *xstrdup(char *);
     47 extern char *xmalloc(int);
     48 extern char *xcalloc(int, int);
     49 #else	/* __STDC__ */
     50 extern void xfree();
     51 extern char *xstrdup();
     52 extern char *xmalloc();
     53 extern char *xcalloc();
     54 #endif	/* __STDC__ */
     55 #else	/* MEM_DEBUG */
     56 #define	XFREE		free
     57 #define	XMALLOC		malloc
     58 #define	XCALLOC		calloc
     59 #define	XSTRDUP		strdup
     60 #endif	/* MEM_DEBUG */
     61 
     62 extern char	*nis_data(char *s);
     63 
     64 /* Imported from rpc.nisd/nis_subr_proc.c */
     65 
     66 #define	GETSERVER(o, n) (((o)->DI_data.do_servers.do_servers_val) + n)
     67 #define	MAXSERVER(o)    (o)->DI_data.do_servers.do_servers_len
     68 
     69 /*
     70  * This is a link list of all the directories served by this server.
     71  */
     72 struct nis_dir_list {
     73 	char	*name;
     74 	struct nis_dir_list *next;
     75 };
     76 static struct nis_dir_list *dirlisthead = NULL;
     77 static bool_t dir_init = FALSE;
     78 
     79 DECLRWLOCK(dirlist);
     80 
     81 /* this function must be protected by dirlist */
     82 static int init_dir_list(const char *filename)
     83 {
     84 	FILE	*fr;
     85 	char	buf[BUFSIZ];
     86 	char	*name, *end;
     87 	struct nis_dir_list *tmp;
     88 
     89 	/* initialize only once */
     90 	if (dir_init)
     91 		return (1);
     92 	dir_init = TRUE;
     93 
     94 	fr = fopen(filename, "r");
     95 	if (fr == NULL) {
     96 		/* The server is just starting out */
     97 		return (-1);
     98 	}
     99 	while (fgets(buf, BUFSIZ, fr)) {
    100 		name = buf;
    101 		while (isspace(*name))
    102 			name++;
    103 		end = name;
    104 		while (!isspace(*end))
    105 			end++;
    106 		*end = NULL;
    107 		tmp = XMALLOC(sizeof (struct nis_dir_list));
    108 		if (tmp == NULL) {
    109 			/* Should never really happen */
    110 			fclose(fr);
    111 			return (0);
    112 		}
    113 		if ((tmp->name = strdup(name)) == NULL) {
    114 			/* Should never really happen */
    115 			XFREE(tmp);
    116 			fclose(fr);
    117 			return (0);
    118 		}
    119 		tmp->next = dirlisthead;
    120 		dirlisthead = tmp;
    121 	}
    122 	fclose(fr);
    123 	return (1);
    124 }
    125 
    126 /*
    127  * nis_server_control() controls various aspects of server administration.
    128  */
    129 int
    130 nis_server_control(infotype, op, argp)
    131 	enum NIS_SERVER_INFO	infotype;
    132 	enum NIS_SERVER_OP	op;
    133 	void			*argp;
    134 {
    135 	char	filename[BUFSIZ], tmpname[BUFSIZ];
    136 	char	buf[BUFSIZ];
    137 	FILE	*fr, *fw;
    138 	char	*name, *end;
    139 	int	ss;
    140 	char	oldval;
    141 	char    *dirs;
    142 	int	i;
    143 	int	ret;
    144 	struct stat st;
    145 	struct nis_dir_list *tmp, *prev;
    146 
    147 	filename[0] = NULL;
    148 	strcat(filename, nis_data("serving_list"));
    149 	switch (infotype) {
    150 	    case SERVING_LIST:
    151 		/*
    152 		 * The file "serving_list" contains one directory name per
    153 		 * line.
    154 		 */
    155 		switch (op) {
    156 		    case DIR_ADD:
    157 			WLOCK(dirlist);
    158 			(void) init_dir_list(filename);
    159 			/* Check whether I already serve this directory? */
    160 			for (tmp = dirlisthead; tmp; tmp = tmp->next)
    161 				if (strcasecmp(tmp->name, (char *)argp) == 0) {
    162 					WULOCK(dirlist);
    163 					return (1);
    164 				}
    165 			fw = fopen(filename, "r+");
    166 			if (fw == NULL) {
    167 				ss = stat(filename, &st);
    168 				if (ss == -1 && errno == ENOENT) {
    169 					fw = fopen(filename, "a+");
    170 				}
    171 				if (fw == NULL) {
    172 					syslog(LOG_ERR,
    173 					"could not open file %s for updating",
    174 						filename);
    175 					WULOCK(dirlist);
    176 					return (0);
    177 				}
    178 			}
    179 
    180 			/* Add it to the incore copy */
    181 			tmp = XMALLOC(sizeof (struct nis_dir_list));
    182 			if (tmp == NULL) {
    183 				/* Should never really happen */
    184 				fclose(fw);
    185 				WULOCK(dirlist);
    186 				return (0);
    187 			}
    188 			if ((tmp->name = strdup((char *)argp)) == NULL) {
    189 				/* Should never really happen */
    190 				fclose(fw);
    191 				XFREE(tmp);
    192 				WULOCK(dirlist);
    193 				return (0);
    194 			}
    195 			tmp->next = dirlisthead;
    196 			dirlisthead = tmp;
    197 
    198 			/* Add it to the file */
    199 			while (fgets(buf, BUFSIZ, fw)) {
    200 				name = buf;
    201 				while (isspace(*name))
    202 					name++;
    203 				end = name;
    204 				while (!isspace(*end))
    205 					end++;
    206 				*end = NULL;
    207 				if (strcasecmp(name, (char *)argp) == 0) {
    208 					/* already exists */
    209 					fclose(fw);
    210 					WULOCK(dirlist);
    211 					return (1);
    212 				}
    213 			}
    214 			fprintf(fw, "%s\n", (char *)argp);
    215 			fclose(fw);
    216 			WULOCK(dirlist);
    217 			return (1);
    218 
    219 		    case DIR_DELETE:
    220 			WLOCK(dirlist);
    221 			(void) init_dir_list(filename);
    222 			prev = dirlisthead;
    223 			for (tmp = dirlisthead; tmp; tmp = tmp->next) {
    224 				if (strcasecmp(tmp->name, (char *)argp) == 0) {
    225 					if (tmp == dirlisthead)
    226 						dirlisthead = tmp->next;
    227 					else
    228 						prev->next = tmp->next;
    229 					XFREE(tmp->name);
    230 					XFREE(tmp);
    231 					break;
    232 				}
    233 				prev = tmp;
    234 			}
    235 			if (tmp == NULL) {
    236 				/* It wasnt found, so return success */
    237 				WULOCK(dirlist);
    238 				return (1);
    239 			}
    240 
    241 			fr = fopen(filename, "r");
    242 			if (fr == NULL) {
    243 				syslog(LOG_ERR,
    244 				"could not open file %s for reading",
    245 					filename);
    246 				WULOCK(dirlist);
    247 				return (0);
    248 			}
    249 			sprintf(tmpname, "%s.tmp", filename);
    250 			fw = fopen(tmpname, "w");
    251 			if (fw == NULL) {
    252 				syslog(LOG_ERR,
    253 				"could not open file %s for updating",
    254 					tmpname);
    255 				fclose(fr);
    256 				WULOCK(dirlist);
    257 				return (0);
    258 			}
    259 			while (fgets(buf, BUFSIZ, fr)) {
    260 				name = buf;
    261 				while (isspace(*name))
    262 					name++;
    263 				end = name;
    264 				while (!isspace(*end))
    265 					end++;
    266 				oldval = *end;
    267 				*end = NULL;
    268 				if (strcasecmp(name, (char *)argp) == 0) {
    269 					continue; /* skip this one */
    270 				}
    271 				*end = oldval;
    272 				fputs(buf, fw);
    273 			}
    274 			fclose(fr);
    275 			fclose(fw);
    276 			rename(tmpname, filename);
    277 			WULOCK(dirlist);
    278 			return (1);
    279 
    280 		    case DIR_INITLIST:
    281 			WLOCK(dirlist);
    282 			ret = init_dir_list(filename);
    283 			WULOCK(dirlist);
    284 			return (ret);
    285 
    286 		    case DIR_GETLIST:
    287 			/* don't acquire write lock unless not inited */
    288 			if (!dir_init) {
    289 				WLOCK(dirlist);
    290 				(void) init_dir_list(filename);
    291 				WULOCK(dirlist);
    292 			}
    293 			i = 0;
    294 			RLOCK(dirlist);
    295 			for (tmp = dirlisthead; tmp; tmp = tmp->next) {
    296 				i += strlen(tmp->name) + 1;
    297 			}
    298 			if (i == 0)
    299 				i = 1;
    300 			dirs = (char *)malloc(i);
    301 			if (dirs == NULL) {
    302 				RULOCK(dirlist);
    303 				return (0);
    304 			}
    305 			dirs[0] = '\0';
    306 			for (tmp = dirlisthead; tmp; tmp = tmp->next) {
    307 				if (*dirs != '\0')
    308 					strcat(dirs, " ");
    309 				strcat(dirs, tmp->name);
    310 			}
    311 			*((char **)argp) = dirs;
    312 			RULOCK(dirlist);
    313 			return (1);
    314 
    315 		    case DIR_SERVED:	/* Do I serve this directory */
    316 			/* don't acquire write lock unless not inited */
    317 			if (!dir_init) {
    318 				WLOCK(dirlist);
    319 				(void) init_dir_list(filename);
    320 				WULOCK(dirlist);
    321 			}
    322 			RLOCK(dirlist);
    323 			for (tmp = dirlisthead; tmp; tmp = tmp->next)
    324 				if (strcasecmp(tmp->name, (char *)argp) == 0) {
    325 					RULOCK(dirlist);
    326 					return (1);
    327 				}
    328 			RULOCK(dirlist);
    329 			return (0);
    330 
    331 		    default:
    332 			return (0);
    333 		}
    334 	    default:
    335 		return (0);
    336 	}
    337 }
    338 
    339 /*
    340  * nis_isserving()
    341  *
    342  * This function returns state indicating whether or not we serve the
    343  * indicated directory.
    344  * 0 = we don't serve it
    345  * n = which server we are (1 == master)
    346  */
    347 int
    348 nis_isserving(nis_object *dobj)
    349 {
    350 	int			ns, i;	/* number of servers */
    351 	nis_name		me = nis_local_host();
    352 
    353 	if (__type_of(dobj) != NIS_DIRECTORY_OBJ)
    354 		return (0);
    355 
    356 	ns = MAXSERVER(dobj);
    357 	/*
    358 	 * POLICY : Should host names be compared in a case independent
    359 	 *	    mode?
    360 	 * ANSWER : Yes, to support the semantics of DNS and existing
    361 	 *	    software which assume hostnames are case insensitive.
    362 	 */
    363 
    364 	if (nis_dir_cmp(me, GETSERVER(dobj, 0)->name) == SAME_NAME)
    365 		return (1);
    366 
    367 	/* Not master, check to see if we serve as a replica */
    368 	for (i = 1; i < ns; i++) {
    369 		if (nis_dir_cmp(me, GETSERVER(dobj, i)->name) == SAME_NAME)
    370 			return (i+1);
    371 	}
    372 	return (0);
    373 }
    374