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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <string.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <pwd.h> 32 #include <sys/stat.h> 33 #include <smbsrv/libsmb.h> 34 #include <smbsrv/libmlsvc.h> 35 #include <smbsrv/smbinfo.h> 36 37 #define SMB_AUTOHOME_KEYSIZ 128 38 #define SMB_AUTOHOME_MAXARG 4 39 #define SMB_AUTOHOME_BUFSIZ 2048 40 41 typedef struct smb_autohome_info { 42 struct smb_autohome_info *magic1; 43 FILE *fp; 44 smb_autohome_t autohome; 45 char buf[SMB_AUTOHOME_BUFSIZ]; 46 char *argv[SMB_AUTOHOME_MAXARG]; 47 int lineno; 48 struct smb_autohome_info *magic2; 49 } smb_autohome_info_t; 50 51 static smb_autohome_info_t smb_ai; 52 53 static smb_autohome_t *smb_autohome_make_entry(smb_autohome_info_t *); 54 static char *smb_autohome_keysub(const char *, char *, int); 55 static smb_autohome_info_t *smb_autohome_getinfo(void); 56 57 /* 58 * Add an autohome share. See smb_autohome(4) for details. 59 * 60 * If share directory contains backslash path separators, they will 61 * be converted to forward slash to support NT/DOS path style for 62 * autohome shares. 63 * 64 * Returns 0 on success or -1 to indicate an error. 65 */ 66 int 67 smb_autohome_add(const char *username) 68 { 69 lmshare_info_t si; 70 char *sharename; 71 smb_autohome_t *ai; 72 73 if (username == NULL) 74 return (-1); 75 76 if ((sharename = strdup(username)) == NULL) 77 return (-1); 78 79 if ((ai = smb_autohome_lookup(sharename)) == NULL) { 80 free(sharename); 81 return (0); 82 } 83 84 (void) memset(&si, 0, sizeof (lmshare_info_t)); 85 (void) strlcpy(si.directory, ai->ah_path, MAXPATHLEN); 86 (void) strsubst(si.directory, '\\', '/'); 87 (void) strlcpy(si.container, ai->ah_container, MAXPATHLEN); 88 89 if (lmshare_is_dir(si.directory) == 0) { 90 free(sharename); 91 return (0); 92 } 93 94 if (lmshare_exists(sharename) != 0) { 95 (void) lmshare_getinfo(sharename, &si); 96 if (!(si.mode & LMSHRM_TRANS)) { 97 free(sharename); 98 return (0); 99 } 100 } else { 101 (void) strcpy(si.share_name, sharename); 102 si.mode = LMSHRM_TRANS; 103 } 104 105 (void) lmshare_add(&si, 0); 106 free(sharename); 107 return (0); 108 } 109 110 /* 111 * Remove an autohome share. 112 * 113 * Returns 0 on success or -1 to indicate an error. 114 */ 115 int 116 smb_autohome_remove(const char *username) 117 { 118 lmshare_info_t si; 119 char *sharename; 120 121 if (username == NULL) 122 return (-1); 123 124 if ((sharename = strdup(username)) == NULL) 125 return (-1); 126 127 if (lmshare_getinfo(sharename, &si) == NERR_Success) { 128 if (si.mode & LMSHRM_TRANS) { 129 (void) lmshare_delete(sharename, 0); 130 } 131 } 132 133 free(sharename); 134 return (0); 135 } 136 137 /* 138 * Find out if a share is an autohome share. 139 * 140 * Returns 1 if the share is an autohome share. 141 * Otherwise returns 0. 142 */ 143 int 144 smb_is_autohome(const lmshare_info_t *si) 145 { 146 if (si && (si->mode & LMSHRM_TRANS) && 147 (lmshare_is_restricted((char *)si->share_name) == 0)) { 148 return (1); 149 } 150 151 return (0); 152 } 153 154 /* 155 * Search the autohome database for the specified name. The name cannot 156 * be an empty string or begin with * or +. 157 * 1. Search the file for the specified name. 158 * 2. Check for the wildcard rule and, if present, treat it as a match. 159 * 3. Check for the nsswitch rule and, if present, lookup the name 160 * via the name services. Note that the nsswitch rule will never 161 * be applied if the wildcard rule is present. 162 * 163 * Returns a pointer to the entry on success or null on failure. 164 */ 165 smb_autohome_t * 166 smb_autohome_lookup(const char *name) 167 { 168 struct passwd *pw; 169 smb_autohome_t *ah = 0; 170 171 if (name == NULL) 172 return (NULL); 173 174 if (*name == '\0' || *name == '*' || *name == '+') 175 return (NULL); 176 177 smb_autohome_setent(); 178 179 while ((ah = smb_autohome_getent(name)) != NULL) { 180 if (strcasecmp(ah->ah_name, name) == 0) 181 break; 182 } 183 184 if (ah == NULL) { 185 smb_autohome_setent(); 186 187 while ((ah = smb_autohome_getent(name)) != NULL) { 188 if (strcasecmp(ah->ah_name, "*") == 0) { 189 ah->ah_name = (char *)name; 190 break; 191 } 192 } 193 } 194 195 if (ah == NULL) { 196 smb_autohome_setent(); 197 198 while ((ah = smb_autohome_getent("+nsswitch")) != NULL) { 199 if (strcasecmp("+nsswitch", ah->ah_name) != 0) 200 continue; 201 if ((pw = getpwnam(name)) == NULL) { 202 ah = 0; 203 break; 204 } 205 206 ah->ah_name = pw->pw_name; 207 208 if (ah->ah_path) 209 ah->ah_container = ah->ah_path; 210 211 ah->ah_path = pw->pw_dir; 212 break; 213 } 214 } 215 216 smb_autohome_endent(); 217 return (ah); 218 } 219 220 /* 221 * Open or rewind the autohome database. 222 */ 223 void 224 smb_autohome_setent(void) 225 { 226 smb_autohome_info_t *si; 227 char *mappath; 228 char filename[MAXNAMELEN]; 229 230 if ((si = smb_autohome_getinfo()) != 0) { 231 (void) fseek(si->fp, 0L, SEEK_SET); 232 si->lineno = 0; 233 return; 234 } 235 236 if ((si = &smb_ai) == 0) 237 return; 238 239 smb_config_rdlock(); 240 if ((mappath = smb_config_get(SMB_CI_AUTOHOME_MAP)) == NULL) 241 mappath = SMB_AUTOHOME_PATH; 242 (void) snprintf(filename, MAXNAMELEN, "%s/%s", mappath, 243 SMB_AUTOHOME_FILE); 244 smb_config_unlock(); 245 246 if ((si->fp = fopen(filename, "r")) == NULL) 247 return; 248 249 si->magic1 = si; 250 si->magic2 = si; 251 si->lineno = 0; 252 } 253 254 /* 255 * Close the autohome database and invalidate the autohome info. 256 * We can't zero the whole info structure because the application 257 * should still have access to the data after the file is closed. 258 */ 259 void 260 smb_autohome_endent(void) 261 { 262 smb_autohome_info_t *si; 263 264 if ((si = smb_autohome_getinfo()) != 0) { 265 (void) fclose(si->fp); 266 si->fp = 0; 267 si->magic1 = 0; 268 si->magic2 = 0; 269 } 270 } 271 272 /* 273 * Return the next entry in the autohome database, opening the file 274 * if necessary. Returns null on EOF or error. 275 * 276 * Note that we are not looking for the specified name. The name is 277 * only used for key substitution, so that the caller sees the entry 278 * in expanded form. 279 */ 280 smb_autohome_t * 281 smb_autohome_getent(const char *name) 282 { 283 smb_autohome_info_t *si; 284 char *bp; 285 286 if ((si = smb_autohome_getinfo()) == 0) { 287 smb_autohome_setent(); 288 289 if ((si = smb_autohome_getinfo()) == 0) 290 return (0); 291 } 292 293 /* 294 * Find the next non-comment, non-empty line. 295 * Anything after a # is a comment and can be discarded. 296 * Discard a newline to avoid it being included in the parsing 297 * that follows. 298 * Leading and training whitespace is discarded, and replicated 299 * whitespace is compressed to simplify the token parsing, 300 * although strsep() deals with that better than strtok(). 301 */ 302 do { 303 if (fgets(si->buf, SMB_AUTOHOME_BUFSIZ, si->fp) == 0) 304 return (0); 305 306 ++si->lineno; 307 308 if ((bp = strpbrk(si->buf, "#\r\n")) != 0) 309 *bp = '\0'; 310 311 (void) trim_whitespace(si->buf); 312 bp = strcanon(si->buf, " \t"); 313 } while (*bp == '\0'); 314 315 (void) smb_autohome_keysub(name, si->buf, SMB_AUTOHOME_BUFSIZ); 316 return (smb_autohome_make_entry(si)); 317 } 318 319 /* 320 * Set up an autohome entry from the line buffer. The line should just 321 * contain tokens separated by single whitespace. The line format is: 322 * <username> <home-dir-path> <ADS container> 323 */ 324 static smb_autohome_t * 325 smb_autohome_make_entry(smb_autohome_info_t *si) 326 { 327 char *bp; 328 int i; 329 330 bp = si->buf; 331 332 for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i) 333 si->argv[i] = 0; 334 335 for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i) { 336 do { 337 if ((si->argv[i] = strsep((char **)&bp, " \t")) == 0) 338 break; 339 } while (*(si->argv[i]) == '\0'); 340 341 if (si->argv[i] == 0) 342 break; 343 } 344 345 if ((si->autohome.ah_name = si->argv[0]) == NULL) { 346 /* 347 * Sanity check: the name could be an empty 348 * string but it can't be a null pointer. 349 */ 350 return (0); 351 } 352 353 if ((si->autohome.ah_path = si->argv[1]) == NULL) 354 si->autohome.ah_path = ""; 355 356 if ((si->autohome.ah_container = si->argv[2]) == NULL) 357 si->autohome.ah_container = ""; 358 359 return (&si->autohome); 360 } 361 362 /* 363 * Substitute the ? and & map keys. 364 * ? is replaced by the first character of the name 365 * & is replaced by the whole name. 366 */ 367 static char * 368 smb_autohome_keysub(const char *name, char *buf, int buflen) 369 { 370 char key[SMB_AUTOHOME_KEYSIZ]; 371 char *ampersand; 372 char *tmp; 373 374 (void) strlcpy(key, buf, SMB_AUTOHOME_KEYSIZ); 375 376 if ((tmp = strpbrk(key, " \t")) == NULL) 377 return (NULL); 378 379 *tmp = '\0'; 380 381 if (strcmp(key, "*") == 0 && name != NULL) 382 (void) strlcpy(key, name, SMB_AUTOHOME_KEYSIZ); 383 384 (void) strsubst(buf, '?', *key); 385 386 while ((ampersand = strchr(buf, '&')) != NULL) { 387 if ((tmp = strdup(ampersand + 1)) == NULL) 388 return (0); 389 390 (void) strlcpy(ampersand, key, buflen); 391 (void) strlcat(ampersand, tmp, buflen); 392 free(tmp); 393 } 394 395 return (buf); 396 } 397 398 /* 399 * Get a pointer to the context buffer and validate it. 400 */ 401 static smb_autohome_info_t * 402 smb_autohome_getinfo(void) 403 { 404 smb_autohome_info_t *si; 405 406 if ((si = &smb_ai) == 0) 407 return (0); 408 409 if ((si->magic1 == si) && (si->magic2 == si) && (si->fp != NULL)) 410 return (si); 411 412 return (0); 413 } 414