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 2008 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 path[MAXNAMELEN]; 228 char filename[MAXNAMELEN]; 229 int rc; 230 231 if ((si = smb_autohome_getinfo()) != 0) { 232 (void) fseek(si->fp, 0L, SEEK_SET); 233 si->lineno = 0; 234 return; 235 } 236 237 if ((si = &smb_ai) == 0) 238 return; 239 240 rc = smb_config_getstr(SMB_CI_AUTOHOME_MAP, path, sizeof (path)); 241 if (rc != SMBD_SMF_OK) 242 return; 243 244 (void) snprintf(filename, MAXNAMELEN, "%s/%s", path, 245 SMB_AUTOHOME_FILE); 246 247 if ((si->fp = fopen(filename, "r")) == NULL) 248 return; 249 250 si->magic1 = si; 251 si->magic2 = si; 252 si->lineno = 0; 253 } 254 255 /* 256 * Close the autohome database and invalidate the autohome info. 257 * We can't zero the whole info structure because the application 258 * should still have access to the data after the file is closed. 259 */ 260 void 261 smb_autohome_endent(void) 262 { 263 smb_autohome_info_t *si; 264 265 if ((si = smb_autohome_getinfo()) != 0) { 266 (void) fclose(si->fp); 267 si->fp = 0; 268 si->magic1 = 0; 269 si->magic2 = 0; 270 } 271 } 272 273 /* 274 * Return the next entry in the autohome database, opening the file 275 * if necessary. Returns null on EOF or error. 276 * 277 * Note that we are not looking for the specified name. The name is 278 * only used for key substitution, so that the caller sees the entry 279 * in expanded form. 280 */ 281 smb_autohome_t * 282 smb_autohome_getent(const char *name) 283 { 284 smb_autohome_info_t *si; 285 char *bp; 286 287 if ((si = smb_autohome_getinfo()) == 0) { 288 smb_autohome_setent(); 289 290 if ((si = smb_autohome_getinfo()) == 0) 291 return (0); 292 } 293 294 /* 295 * Find the next non-comment, non-empty line. 296 * Anything after a # is a comment and can be discarded. 297 * Discard a newline to avoid it being included in the parsing 298 * that follows. 299 * Leading and training whitespace is discarded, and replicated 300 * whitespace is compressed to simplify the token parsing, 301 * although strsep() deals with that better than strtok(). 302 */ 303 do { 304 if (fgets(si->buf, SMB_AUTOHOME_BUFSIZ, si->fp) == 0) 305 return (0); 306 307 ++si->lineno; 308 309 if ((bp = strpbrk(si->buf, "#\r\n")) != 0) 310 *bp = '\0'; 311 312 (void) trim_whitespace(si->buf); 313 bp = strcanon(si->buf, " \t"); 314 } while (*bp == '\0'); 315 316 (void) smb_autohome_keysub(name, si->buf, SMB_AUTOHOME_BUFSIZ); 317 return (smb_autohome_make_entry(si)); 318 } 319 320 /* 321 * Set up an autohome entry from the line buffer. The line should just 322 * contain tokens separated by single whitespace. The line format is: 323 * <username> <home-dir-path> <ADS container> 324 */ 325 static smb_autohome_t * 326 smb_autohome_make_entry(smb_autohome_info_t *si) 327 { 328 char *bp; 329 int i; 330 331 bp = si->buf; 332 333 for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i) 334 si->argv[i] = 0; 335 336 for (i = 0; i < SMB_AUTOHOME_MAXARG; ++i) { 337 do { 338 if ((si->argv[i] = strsep((char **)&bp, " \t")) == 0) 339 break; 340 } while (*(si->argv[i]) == '\0'); 341 342 if (si->argv[i] == 0) 343 break; 344 } 345 346 if ((si->autohome.ah_name = si->argv[0]) == NULL) { 347 /* 348 * Sanity check: the name could be an empty 349 * string but it can't be a null pointer. 350 */ 351 return (0); 352 } 353 354 if ((si->autohome.ah_path = si->argv[1]) == NULL) 355 si->autohome.ah_path = ""; 356 357 if ((si->autohome.ah_container = si->argv[2]) == NULL) 358 si->autohome.ah_container = ""; 359 360 return (&si->autohome); 361 } 362 363 /* 364 * Substitute the ? and & map keys. 365 * ? is replaced by the first character of the name 366 * & is replaced by the whole name. 367 */ 368 static char * 369 smb_autohome_keysub(const char *name, char *buf, int buflen) 370 { 371 char key[SMB_AUTOHOME_KEYSIZ]; 372 char *ampersand; 373 char *tmp; 374 int bufsize = buflen; 375 376 (void) strlcpy(key, buf, SMB_AUTOHOME_KEYSIZ); 377 378 if ((tmp = strpbrk(key, " \t")) == NULL) 379 return (NULL); 380 381 *tmp = '\0'; 382 383 /* 384 * Substitution characters are not allowed in the key. 385 */ 386 if (strpbrk(key, "?&") != NULL) 387 return (NULL); 388 389 if (strcmp(key, "*") == 0 && name != NULL) 390 (void) strlcpy(key, name, SMB_AUTOHOME_KEYSIZ); 391 392 (void) strsubst(buf, '?', *key); 393 394 while ((ampersand = strchr(buf, '&')) != NULL) { 395 if ((tmp = strdup(ampersand + 1)) == NULL) 396 return (0); 397 398 bufsize = buflen - (ampersand - buf); 399 (void) strlcpy(ampersand, key, bufsize); 400 (void) strlcat(ampersand, tmp, bufsize); 401 free(tmp); 402 } 403 404 return (buf); 405 } 406 407 /* 408 * Get a pointer to the context buffer and validate it. 409 */ 410 static smb_autohome_info_t * 411 smb_autohome_getinfo(void) 412 { 413 smb_autohome_info_t *si; 414 415 if ((si = &smb_ai) == 0) 416 return (0); 417 418 if ((si->magic1 == si) && (si->magic2 == si) && (si->fp != NULL)) 419 return (si); 420 421 return (0); 422 } 423