/* * Copyright (c) 2009 * AVM GmbH, Berlin, Germany * * License: Free, use with no restriction. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "usermap.h" enum parse_state { LEADING_SPACES, OPTIONAL_LEADING_QUOTE, IN_NAME, TRAILING_SPACES, COLON, NAME_COMPLETE, PARSE_ERROR }; static void EnumUserMaps(void *ctx, int (*callback)(void *ctx, char *friendly_name, char *linux_name)) { FILE *fp = fopen("/var/tmp/users.map", "rt"); if (!fp) return; char *linux_name = 0; char buf[128]; while(buf == fgets(buf, sizeof(buf)-1, fp)) { char *start; buf[sizeof(buf)-1] = '\0'; if (buf[0] == '#' || buf[0] == ';') continue; // comment line // have to skip ! if used for smbd username map option if (buf[0] == '!') start = buf + 1; else start = buf; char *p = strchr(start, '='); if (!p) continue; char *p2 = p-1; while(p2 > start && isspace(*p2)) p2--; if (p2 < start) continue; if (linux_name) free(linux_name); linux_name = (char *)malloc(p2-start+1+1); if (!linux_name) continue; memcpy(linux_name, start, p2-start+1); linux_name[p2-start+1] = '\0'; p++; char *name_start = NULL, *name_end = NULL; enum parse_state state = LEADING_SPACES; short bQuoted = 0; while(state != PARSE_ERROR) { if ((state != IN_NAME || bQuoted) && (*p == '\0' || *p == '\r' || *p == '\n')) break; // while switch(state) { case LEADING_SPACES: while(isspace(*p)) p++; state = OPTIONAL_LEADING_QUOTE; break; case OPTIONAL_LEADING_QUOTE: if (*p == '\"') { bQuoted = 1; p++; name_start = p; } else { name_start = p++; } state = IN_NAME; break; case IN_NAME: if (bQuoted) { if (*p == '\"') { name_end = p ; state = NAME_COMPLETE; bQuoted = 0; } p++; } else { if (isspace(*p) || *p == ',' || *p == '\0' || *p == '\r' ||*p == '\n') { name_end = p; state = NAME_COMPLETE; } else p++; } break; case TRAILING_SPACES: while(isspace(*p)) p++; state = COLON; break; case COLON: if (*p != ',') state = PARSE_ERROR; // parse_error else { p++; state = LEADING_SPACES; } break; } // switch if (state == NAME_COMPLETE) { state = TRAILING_SPACES; if (name_end > name_start) { char *friendly_name = (char *)malloc(name_end - name_start + 1); if (friendly_name) { memcpy(friendly_name, name_start, name_end - name_start); friendly_name[name_end - name_start] = '\0'; int stop = callback(ctx, friendly_name, linux_name); free(friendly_name); if (stop) goto end; } } } } // while } // while end: fclose(fp); if (linux_name) free(linux_name); } struct mapuser_ctx { const char *name; char *map_buffer; size_t map_size; short found; }; static int mapuser_enum(void *context, char *friendly_name, char *linux_name) { struct mapuser_ctx *ctx = (struct mapuser_ctx *)context; // * matches every ctx->name if (strcmp(friendly_name, "*")) { if (strcasecmp(ctx->name, friendly_name)) return 0; } strncpy(ctx->map_buffer, linux_name, ctx->map_size); ctx->map_buffer[ctx->map_size-1] = '\0'; ctx->found = 1; return 1; } const char *usermap_mapuser(const char *name, char *map_buffer, size_t map_size) { struct mapuser_ctx ctx; ctx.name = name; ctx.map_buffer = map_buffer; ctx.map_size = map_size; ctx.found = 0; EnumUserMaps((void *)&ctx, mapuser_enum); if (ctx.found) return map_buffer; else return name; } struct anonymous_check_ctx { unsigned nuser; short ftpuser; }; static int anonymous_check_enum(void *context, char *friendly_name, char *linux_name) { struct anonymous_check_ctx *ctx = (struct anonymous_check_ctx *)context; ctx->nuser++; if (ctx->nuser > 1) return 1; if (!strcmp(friendly_name, "ftpuser")) ctx->ftpuser = 1; return 0; } struct find_userid_ctx { int found; unsigned uid; char **pusername; }; static int find_enabled_userid_enum(void *context, char *friendly_name, char *linux_name) { struct find_userid_ctx *ctx = (struct find_userid_ctx *)context; char name[20]; snprintf(name, sizeof(name), "boxusr%u", ctx->uid); if (!strcmp(linux_name, name)) { if (ctx->pusername) *(ctx->pusername) = strdup(friendly_name); ctx->found = 1; return 1; } return 0; } int usermap_is_compatibility_mode(void) { struct find_userid_ctx ctx; ctx.found = 0; ctx.uid = 100; ctx.pusername = 0; EnumUserMaps((void *)&ctx, find_enabled_userid_enum); return ctx.found; } int usermap_is_skip_auth_from_homenetwork(char **pskip_username) { struct find_userid_ctx ctx; ctx.found = 0; ctx.uid = 101; ctx.pusername = pskip_username; EnumUserMaps((void *)&ctx, find_enabled_userid_enum); return ctx.found; } int usermap_is_anonymous_allowed(void) { struct anonymous_check_ctx ctx; ctx.nuser = 0; ctx.ftpuser = 0; EnumUserMaps((void *)&ctx, anonymous_check_enum); return (ctx.nuser == 1 && ctx.ftpuser); }