From 6ca83b9d015479ccddc45598974da2045bea3033 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 3 Aug 2009 16:52:01 +0200 Subject: [PATCH] Support NetWkstaGetInfo 101 and 102 --- source3/configure.in | 2 +- source3/rpc_server/srv_wkssvc_nt.c | 128 +++++++++++++++++++++++++++++++---- 2 files changed, 114 insertions(+), 16 deletions(-) diff --git a/source3/configure.in b/source3/configure.in index 7cfd3fb..068f9cd 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -2016,7 +2016,7 @@ dnl We need to check for many of them dnl But we don't need to do each and every one, because our code uses dnl mostly just the utmp (not utmpx) fields. -AC_CHECK_FUNCS(pututline pututxline updwtmp updwtmpx getutmpx) +AC_CHECK_FUNCS(pututline pututxline updwtmp updwtmpx getutmpx getutxent) AC_CACHE_CHECK([for ut_name in utmp],samba_cv_HAVE_UT_UT_NAME,[ AC_TRY_COMPILE([#include diff -u a/source3/include/config.h.in b/source3/include/config.h.in >>smb.patch --- a/source3/include/config.h.in 2008-09-18 04:58:36.000000000 -0700 +++ b/source3/include/config.h.in 2009-08-06 13:42:20.000000000 -0700 @@ -676,6 +676,9 @@ /* Define to 1 if you have the `getutmpx' function. */ #undef HAVE_GETUTMPX +/* Define to 1 if you have the `getutxent' function. */ +#undef HAVE_GETUTXENT + /* Define to 1 if you have the `getxattr' function. */ #undef HAVE_GETXATTR diff --git a/source3/rpc_server/srv_wkssvc_nt.c b/source3/rpc_server/srv_wkssvc_nt.c index b06818e..0f889db 100644 --- a/source3/rpc_server/srv_wkssvc_nt.c +++ b/source3/rpc_server/srv_wkssvc_nt.c @@ -29,12 +29,54 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV +#ifdef HAVE_GETUTXENT + +#include + +static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) +{ + char **users = NULL; + int num_users = 0; + struct utmpx *u; + + while ((u = getutxent()) != NULL) { + char **tmp; + tmp = talloc_realloc(mem_ctx, users, char *, num_users+1); + if (tmp == NULL) { + return NULL; + } + users = tmp; + users[num_users] = talloc_strdup(users, u->ut_user); + if (users[num_users] == NULL) { + TALLOC_FREE(users); + return NULL; + } + } + return users; +} + +#else + +static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) +{ + return NULL; +} + +#endif + /******************************************************************* Fill in the values for the struct wkssvc_NetWkstaInfo100. ********************************************************************/ -static void create_wks_info_100(struct wkssvc_NetWkstaInfo100 *info100) +static struct wkssvc_NetWkstaInfo100 *create_wks_info_100(TALLOC_CTX *mem_ctx) { + struct wkssvc_NetWkstaInfo100 *info100; + + info100 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo100); + if (info100 == NULL) { + return NULL; + } + info100->platform_id = PLATFORM_ID_NT; /* unknown */ info100->version_major = lp_major_announce_version(); info100->version_minor = lp_minor_announce_version(); @@ -44,7 +86,56 @@ static void create_wks_info_100(struct wkssvc_NetWkstaInfo100 *info100) info100->domain_name = talloc_asprintf_strupper_m( info100, "%s", lp_workgroup()); - return; + return info100; +} + +static struct wkssvc_NetWkstaInfo101 *create_wks_info_101(TALLOC_CTX *mem_ctx) +{ + struct wkssvc_NetWkstaInfo101 *info101; + + info101 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo101); + if (info101 == NULL) { + return NULL; + } + + info101->platform_id = PLATFORM_ID_NT; /* unknown */ + info101->version_major = lp_major_announce_version(); + info101->version_minor = lp_minor_announce_version(); + + info101->server_name = talloc_asprintf_strupper_m( + info101, "%s", global_myname()); + info101->domain_name = talloc_asprintf_strupper_m( + info101, "%s", lp_workgroup()); + info101->lan_root = NULL; + + return info101; +} + +static struct wkssvc_NetWkstaInfo102 *create_wks_info_102(TALLOC_CTX *mem_ctx) +{ + struct wkssvc_NetWkstaInfo102 *info102; + char **users; + + info102 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo102); + if (info102 == NULL) { + return NULL; + } + + info102->platform_id = PLATFORM_ID_NT; /* unknown */ + info102->version_major = lp_major_announce_version(); + info102->version_minor = lp_minor_announce_version(); + + info102->server_name = talloc_asprintf_strupper_m( + info102, "%s", global_myname()); + info102->domain_name = talloc_asprintf_strupper_m( + info102, "%s", lp_workgroup()); + info102->lan_root = NULL; + + users = get_logged_on_userlist(talloc_tos()); + info102->logged_on_users = talloc_array_length(users); + TALLOC_FREE(users); + + return info102; } /******************************************************************** @@ -53,22 +144,29 @@ static void create_wks_info_100(struct wkssvc_NetWkstaInfo100 *info100) WERROR _wkssvc_NetWkstaGetInfo(pipes_struct *p, struct wkssvc_NetWkstaGetInfo *r) { - struct wkssvc_NetWkstaInfo100 *wks100 = NULL; - - /* We only support info level 100 currently */ - - if ( r->in.level != 100 ) { + switch (r->in.level) { + case 100: + r->out.info->info100 = create_wks_info_100(p->mem_ctx); + if (r->out.info->info100 == NULL) { + return WERR_NOMEM; + } + break; + case 101: + r->out.info->info101 = create_wks_info_101(p->mem_ctx); + if (r->out.info->info101 == NULL) { + return WERR_NOMEM; + } + break; + case 102: + r->out.info->info102 = create_wks_info_102(p->mem_ctx); + if (r->out.info->info102 == NULL) { + return WERR_NOMEM; + } + break; + default: return WERR_UNKNOWN_LEVEL; } - if ( (wks100 = TALLOC_ZERO_P(p->mem_ctx, struct wkssvc_NetWkstaInfo100)) == NULL ) { - return WERR_NOMEM; - } - - create_wks_info_100( wks100 ); - - r->out.info->info100 = wks100; - return WERR_OK; } -- 1.6.0.1 From 51256d7f8fdea4e00c92af268328b5bbf2a965a5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 3 Aug 2009 17:27:11 +0200 Subject: [PATCH] First cut at _wkssvc_NetWkstaEnumUsers This needs access checks! --- source3/rpc_server/srv_wkssvc_nt.c | 55 ++++++++++++++++++++++++++++++++++-- 1 files changed, 52 insertions(+), 3 deletions(-) diff --git a/source3/rpc_server/srv_wkssvc_nt.c b/source3/rpc_server/srv_wkssvc_nt.c index 0f889db..b1deceb 100644 --- a/source3/rpc_server/srv_wkssvc_nt.c +++ b/source3/rpc_server/srv_wkssvc_nt.c @@ -41,6 +41,9 @@ static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) while ((u = getutxent()) != NULL) { char **tmp; + if (u->ut_type != USER_PROCESS) { + continue; + } tmp = talloc_realloc(mem_ctx, users, char *, num_users+1); if (tmp == NULL) { return NULL; @@ -51,6 +54,7 @@ static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) TALLOC_FREE(users); return NULL; } + num_users += 1; } return users; } @@ -180,14 +184,59 @@ WERROR _wkssvc_NetWkstaSetInfo(pipes_struct *p, struct wkssvc_NetWkstaSetInfo *r return WERR_NOT_SUPPORTED; } +static struct wkssvc_NetWkstaEnumUsersCtr0 *create_enum_users0( + TALLOC_CTX *mem_ctx) +{ + struct wkssvc_NetWkstaEnumUsersCtr0 *ctr0; + char **users; + int i, num_users; + + ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr0); + if (ctr0 == NULL) { + return NULL; + } + + users = get_logged_on_userlist(talloc_tos()); + if (users == NULL) { + TALLOC_FREE(ctr0); + return NULL; + } + + num_users = talloc_array_length(users); + ctr0->entries_read = num_users; + ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0, + num_users); + if (ctr0->user0 == NULL) { + TALLOC_FREE(ctr0); + TALLOC_FREE(users); + return NULL; + } + + for (i=0; iuser0[i].user_name = talloc_move(ctr0->user0, &users[i]); + } + TALLOC_FREE(users); + return ctr0; +} + /******************************************************************** ********************************************************************/ WERROR _wkssvc_NetWkstaEnumUsers(pipes_struct *p, struct wkssvc_NetWkstaEnumUsers *r) { - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; + if (r->in.info->level != 0) { + return WERR_UNKNOWN_LEVEL; + } + + r->out.info->ctr.user0 = create_enum_users0(p->mem_ctx); + if (r->out.info->ctr.user0 == NULL) { + return WERR_NOMEM; + } + r->out.info->level = r->in.info->level; + *r->out.entries_read = r->out.info->ctr.user0->entries_read; + *r->out.resume_handle = 0; + + return WERR_OK; } /******************************************************************** -- 1.6.0.1 diff -u a/source/rpc_server/srv_wkssvc_nt.c b/source3/rpc_server/srv_wkssvc_nt.c --- a/source/rpc_server/srv_wkssvc_nt.c 2009-08-06 13:59:23.000000000 -0700 +++ b/source3/rpc_server/srv_wkssvc_nt.c 2009-08-06 13:39:44.000000000 -0700 @@ -32,29 +32,127 @@ #include +static char *get_proc_user(TALLOC_CTX *mem_ctx, __pid_t pid) +{ + /* Return the name of the user who created a process: */ + + struct stat st; + struct passwd *pw; + char *uname; + char path[32]; + + snprintf(path, sizeof(path), "/proc/%d", pid); + if (stat(path, &st) == -1) { + return NULL; + } + pw = getpwuid_alloc(mem_ctx, st.st_uid); + if (!pw) { + return NULL; + } + uname = talloc_strdup(mem_ctx, pw->pw_name); + TALLOC_FREE(pw); + + return (uname); +} + static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) { char **users = NULL; + __pid_t *pids = NULL; + struct timeval *login_times = NULL; + char *proc_uname; int num_users = 0; + int i; + bool reordered; struct utmpx *u; while ((u = getutxent()) != NULL) { char **tmp; + __pid_t *tmp2; + struct timeval *tmp3; if (u->ut_type != USER_PROCESS) { continue; } + for (i = 0; i < num_users; i++) { + /* getutxent can return multiple user entries for the + * same login process, so ignore dups */ + if (u->ut_pid == pids[i]) break; + } + if (i < num_users) { + DEBUG(3,("Ignored user %s dup pid %d\n", u->ut_user, u->ut_pid)); + continue; + } + proc_uname = get_proc_user(mem_ctx, u->ut_pid); + if (proc_uname) { + /* When a user first logs in their login process is created by root, + * and if they then subsequently re-login the login process will be + * created by the user. So if the latter is the case and we already + * have an entry for the user name, don't re-add it */ + bool is_relogin = False; + if (strcmp(proc_uname, u->ut_user) == 0) { + for (i = 0; i < num_users; i++) { + if (strcmp(users[i], u->ut_user) == 0) { + is_relogin = True; + break; + } + } + } + TALLOC_FREE(proc_uname); + if (is_relogin) { + DEBUG(3,("Ignored user %s relogin\n", u->ut_user)); + continue; + } + } + tmp = talloc_realloc(mem_ctx, users, char *, num_users+1); - if (tmp == NULL) { + tmp2 = talloc_realloc(mem_ctx, pids, int, num_users+1); + tmp3 = talloc_realloc(mem_ctx, login_times, struct timeval, num_users+1); + if (tmp == NULL || tmp2 == NULL || tmp3 == NULL) { + if (tmp) TALLOC_FREE(tmp); + if (tmp2) TALLOC_FREE(tmp2); + if (tmp3) TALLOC_FREE(tmp3); + endutent(); return NULL; } users = tmp; + pids = tmp2; + login_times = tmp3; users[num_users] = talloc_strdup(users, u->ut_user); if (users[num_users] == NULL) { TALLOC_FREE(users); + TALLOC_FREE(pids); + TALLOC_FREE(login_times); + endutent(); return NULL; } + pids[num_users] = u->ut_pid; + login_times[num_users].tv_sec = u->ut_tv.tv_sec; + login_times[num_users].tv_usec = u->ut_tv.tv_usec; num_users += 1; } + + /* Sort the user list by time, oldest first */ + do { + reordered = False; + for (i = 0; i < num_users-1; i++) { + if (login_times[i].tv_sec > login_times[i+1].tv_sec + || (login_times[i].tv_sec == login_times[i+1].tv_sec + && login_times[i].tv_usec > login_times[i+1].tv_usec)) { + char *tmp1 = users[i]; + struct timeval tmp2 = login_times[i]; + users[i] = users[i+1]; + users[i+1] = tmp1; + login_times[i] = login_times[i+1]; + login_times[i+1] = tmp2; + reordered = True; + } + } + } while (reordered); + + TALLOC_FREE(pids); + TALLOC_FREE(login_times); + endutent(); + errno = 0; return users; } @@ -136,6 +234,7 @@ users = get_logged_on_userlist(talloc_tos()); info102->logged_on_users = talloc_array_length(users); + TALLOC_FREE(users); return info102; @@ -196,25 +295,27 @@ } users = get_logged_on_userlist(talloc_tos()); - if (users == NULL) { + if (users == NULL && errno != 0) { + DEBUG(1,("get_logged_on_userlist error %d: %s\n", + errno, strerror(errno))); TALLOC_FREE(ctr0); return NULL; } - num_users = talloc_array_length(users); + num_users = (users) ? talloc_array_length(users) : 0; ctr0->entries_read = num_users; ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0, num_users); if (ctr0->user0 == NULL) { TALLOC_FREE(ctr0); - TALLOC_FREE(users); + if (users) TALLOC_FREE(users); return NULL; } for (i=0; iuser0[i].user_name = talloc_move(ctr0->user0, &users[i]); } - TALLOC_FREE(users); + if (users) TALLOC_FREE(users); return ctr0; }