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