Users, Groups, and Security


The UNIX and Windows security models are quite different. Win32 uses the underlying Windows security model. This results in some key differences between the way Win32 security works and the way UNIX security works. (Some of these differences have already been covered in Comparison of Windows and UNIX Architectures in Chapter 2, Windows and UNIX Compared.) This section covers the differences in the security model and how you should modify your code to operate in Win32.

The key areas that are addressed here are:

  • A comparison of the UNIX and Win32 user and group APIs

  • Adding a new group

  • Adding a user to a group

  • Listing groups

  • Adding a user account

  • Changing a user s password

  • Removing a user account

  • Getting user information about all users

  • Getting information about a specific user

  • Retrieving the current user s user name

  • Security functions

UNIX and Win32 User and Group Functions

This section describes the different user and group functions for UNIX and Win32.

UNIX User and Group Functions

Table 9.9 shows user and group management functions that control user and group accounts in a security database. To link some of the code examples that use these functions, you must add -lcrypt to the gcc option list.

Table 9.9: UNIX User and Group Functions ” Security

Function

Description

Group database functions

 

endgrent

Close database

fgetgrent, fgetgrent_r

Get next Group database entry from FILE Stream

getgrent, getgrent_r

Get next Group database entry

getgrgid, getgrgid_r

Get Group database entry with Group ID

getgrnam, getgrnam_r

Get Group database entry with Name

setgrent

Rewind database

Supplementary group access list functions

 

getgroups

Get

initgroups

Initialize

setgroups

Set

User shadow database functions

 

endspent

Close database

fgetspent, fgetspent_r

Get next User Shadow database entry from FILE Stream

getspent, getspent_r

Get next User Shadow database entry

getspnam, getspnam_r

Get User Shadow database entry with Name

setspent

Rewind database

User database functions

 

endpwent

Close database

fgetpwent, fgetpwent_r

Get next User database entry from FILE Stream

getpw

User database get function to get passwd entry from UID

getpwent, getpwent_r

Get next User database entry

getpwnam, getpwnam_r

Get User database entry with Name

getpwuid, getpwuid_r

Get User database entry with User ID

setpwent

Rewind database

User database Lock/UnLock functions

 

lckpwdf

Lock function

ulckpwdf

UnLock function

User database Write functions

 

putgrent

Write group file entry

putpwent

Write password file entry

putspent

Write shadow password file entry

Win32 User Functions

Table 9.10 shows Win32 user management functions that control a user s account in a security database. To link these functions in the example code later in this section, you must add Netapi32.lib to the Visual Studio project link-library list.

Table 9.10: Win32 User and Group Functions ” Security

Function

Description

NetUserAdd

Adds a user account and assigns a password and privilege level.

NetUserChangePassword

Changes a user s password for a specified network server or domain.

NetUserDel

Deletes a user account from the server.

NetUserEnum

Lists all user accounts on a server.

NetUserGetGroups

Returns a list of global group names to which a user belongs.

NetUserGetInfo

Returns information about a particular user account on a server.

NetUserGetLocalGroups

Returns a list of local group names to which a user belongs.

NetUserSetGroups

Sets global group memberships for a specified user account.

NetUserSetInfo

Sets the password and other elements of a user account.

User account information is available at the following levels:

  • USER_INFO_0

  • USER_INFO_1

  • USER_INFO_2

  • USER_INFO_3

  • USER_INFO_4

  • USER_INFO_10

  • USER_INFO_11

  • USER_INFO_20

  • USER_INFO_21

  • USER_INFO_22

  • USER_INFO_23

In addition, the following information levels are valid when you call the NetUserSetInfo function:

  • USER_INFO_1003

  • USER_INFO_1005

  • USER_INFO_1006

  • USER_INFO_1007

  • USER_INFO_1008

  • USER_INFO_1009

  • USER_INFO_1010

  • USER_INFO_1011

  • USER_INFO_1012

  • USER_INFO_1014

  • USER_INFO_1017

  • USER_INFO_1020

  • USER_INFO_1024

  • USER_INFO_1051

  • USER_INFO_1052

  • USER_INFO_1053

Win32 Group Functions

The network management provides functions for both local groups and global groups.

Local Group

A local group can contain user accounts or global group accounts from one or more domains. (Global groups can contain users from only one domain.) A local group shares common privileges and rights only within its own domain.

The network management local group functions control members of local groups in a way that the functions can only be called locally on the system on which the local group is defined. On a Windows NT, Windows 2000, or Windows XP workstation,or on a server that is not a domain controller, you can use only a local group defined on that system. A local group defined on the primary domain controller is replicated to all other domain controllers in the domain. Therefore, a local group is availableon all domain controllers within the domain in which it was created.

The local group functions create or delete local groups, and review or adjust the memberships of local groups. These functions are shown in Table 9.11 on the next page.

Table 9.11: Win32 Local Group Functions

Function

Description

NetLocalGroupAdd

Creates a local group.

NetLocalGroupAddMembers

Adds one or more users or global groups to an existing local group.

NetLocalGroupDel

Deletes a local group, removing all existing members from the group.

NetLocalGroupDelMembers

Removes one or more members from an existing local group

NetLocalGroupEnum

Returns information about each local group account on a server.

NetLocalGroupGetInfo

Returns information about a particular local group account on a server.

NetLocalGroupGetMembers

Lists all members of a specified local group.

NetLocalGroupSetInfo

Sets general information about a local group.

NetLocalGroupSetMembers

Assigns members to a local group.

Global Group

A global group contains user accounts from one domain that are grouped together under one group account name. A global group can contain only members (users) from the domain where the global group is created; it cannot contain local groupsor other global groups. A global group is available within its own domain and within any trusting domain.

The network management group functions control global groups. Table 9.12 shows these group functions.

Table 9.12: Win32 Network Management (Global Group) Functions

Function

Description

NetGroupAdd

Creates a global group.

NetGroupAddUser

Adds one user to an existing global group.

NetGroupDel

Removes a global group whether or not the group has any members.

NetGroupDelUser

Removes one user name from a global group.

NetGroupEnum

Lists all global groups on a server.

NetGroupGetInfo

Returns information about a particular global group.

NetGroupGetUsers

Lists all members of a particular global group.

NetGroupSetInfo

Sets general information about a global group.

NetGroupSetUsers

Assigns members to a new global group. Replaces the members of an existing group.

Global group account information is available at the following levels:

  • GROUP_INFO_0

  • GROUP_INFO_1

  • GROUP_INFO_2

  • GROUP_INFO_3

  • GROUP_INFO_1002

  • GROUP_INFO_1005

Adding a New Group

The following examples illustrate migrating code from UNIX to Windows to adda new group.

UNIX Example: Adding a New Group

This example uses the getgrnam and getgruid functions to verify that a group account and gid does not already exists before adding a new group account with the putgrent function.

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <grp.h> int main(int argc, char *argv[]) {     struct group a_group;     struct group *ptr_group;     char gr_name[20];     char gr_passwd[] = "";     char *gr_mem[] = {0};     int i, gid;     a_group.gr_name = gr_name;     a_group.gr_passwd = gr_passwd;     a_group.gr_mem = gr_mem;     if (argc != 3)     {        printf("Usage: %s GroupName GID\n", argv[0]);        exit(1);     } // Call the getpwnam function to check if user exists.     if(ptr_group = getgrnam (argv[1])) {         printf("Group already exists\n");         exit(1);     } // Call the getpwuid function to check if User ID exists     if(ptr_group = getgrgid (gid=(gid_t) atoi(argv[2]))) {         printf("Group ID already exists\n");         exit(1);     }     ptr_group = &a_group;     strcpy (ptr_group->gr_name, argv[1]);     printf ("Group: %s\n", ptr_group->gr_name);     ptr_group->gr_gid = gid;     printf ("gid: %d\n", ptr_group->gr_gid); // Call the putgrent function     putgrent(ptr_group, fopen ("/etc/group", "a+"));     exit(0); } 

Win32 Example: Adding a New Group

This example uses the NetLocalGroupAdd() function to create a local group in the security database.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    LOCALGROUP_INFO_1 lgi;    DWORD dwLevel = 1;    DWORD dwError = 0;    NET_API_STATUS nStatus;    if (argc != 3)    {       fwprintf(stderr, L"Usage: %s \\ServerName GroupName\n", argv[0]);       exit(1);    }    // Set up the LOCALGROUP_INFO_1 structure.     lgi.lgrpi1_name = argv[2];    lgi.lgrpi1_comment = NULL;    nStatus = NetLocalGroupAdd(argv[1],                               dwLevel,                               (LPBYTE)&lgi,                               &dwError);    //    // If the call succeeds, inform the user.    //    if (nStatus == NERR_Success)       fwprintf(stderr, L"Local Group %s has been successfully added on %s\n",                argv[2], argv[1]);    //    // Otherwise, print the system error.    //    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    return 0; } 

Adding a User to a Group

The following examples illustrate migrating code from UNIX to Windows to adda user to a group.

UNIX Example: Adding a User to a Group

This example uses the getgrnam and getpwnam functions to verify that the specified group account exists, and that the user account to be added exists, before creatinga new /etc/group file (named: /etc/groupx) with the added member to the specified group using a combination of the fgetgrent and fprintf functions. This program assumes that the super user will be using this program, and will manually copy /etc/groupx to /etc/group after verifying proper update to the group entry.

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <grp.h> #include <pwd.h> int main(int argc, char *argv[]) {     struct group a_group;     struct group *ptr_group;     struct passwd *ptr_pswd;     int i;     FILE *stream_in, *stream_out;     if (argc != 3)     {        printf("Usage: %s GroupName NewMember\n", argv[0]);        exit(1);     } // Call the getgrnam function to check if group exists.     if(!(ptr_group = getgrnam (argv[1]))) {         printf("group does not exist\n");         exit(1);     } // Call the getpwnam function to check if group exists.     if(!(ptr_pswd = getpwnam (argv[2]))) {         printf("member to be added does not exist\n");         exit(1);     }     ptr_group = &a_group; // Scan /etc/group file, create /etc/groupx, with updated group entry     stream_in = fopen ("/etc/group", "r");     stream_out = fopen ("/etc/groupx", "w");     while(ptr_group = fgetgrent(stream_in)) { i=0;         fprintf(stream_out, "%s:%s:%d:", ptr_group->gr_name,\                 ptr_group->gr_passwd, ptr_group->gr_gid);         while(ptr_group->gr_mem[i] != 0) {             fprintf(stream_out, "%s,", ptr_group->gr_mem[i]);             i++;         }         if(strcmp(ptr_group->gr_name, argv[1]) == 0)             fprintf(stream_out, "%s\n", argv[2]);         else             fprintf(stream_out, "\n");         printf("Next Group: %s\n", ptr_group->gr_name);     }     fclose (stream_in);     fclose (stream_out);     exit(0); } 

Win32 Example: Adding a User to a Group

This example uses the NetLocalGroupAddMembers () function to add membersto a local group in the security database.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    LOCALGROUP_MEMBERS_INFO_3    lgmi;    DWORD dwLevel = 3;    DWORD dwCount = 1;    NET_API_STATUS nStatus;    if (argc != 4)    {       fwprintf(stderr, L"Usage: %s \\ServerName GroupName UserName\n", argv[0]);       exit(1);    }    // Set up the LOCALGROUP_MEMBERS_INFO_3 structure.     lgmi.lgrmi3_domainandname = argv[3];    nStatus = NetLocalGroupAddMembers(argv[1],                                      argv[2],                                      dwLevel,                                      (LPBYTE)&lgmi,                                      dwCount);    //    // If the call succeeds, inform the user.    //    if (nStatus == NERR_Success)       fwprintf(stderr, L"User %s has been successfully added to Local Group %s on %s\n",                argv[3], argv[2], argv[1]);    //    // Otherwise, print the system error.    //    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    return 0; } 

Listing Groups

The following examples illustrate migrating code to list groups from UNIXto Windows.

UNIX Example: Listing Groups

This example uses the getgroups function to retrieve a list of global groups to which the calling user belongs.

 #include <sys/types.h> #include <unistd.h> #include <grp.h> int main() {    struct group *ptr_group;    gid_t grouplist[100];    int num;    num = getgroups (99, grouplist);    printf("group\tID:\n-------------\n");    if (num > 0)       while(num) {          ptr_group = getgrgid(grouplist[num]);          printf("%s\t%d\n", ptr_group->gr_name, grouplist[num]);       }    else       printf("num=%d\n", num);    exit(0); } 

Win32 Example: Listing Groups

This example uses the NetUserGetGroups() function to retrieve a list of global groups to which a specified user belongs. You use the NetUserGetLocalGroups() function to get a list of local groups to which a user belongs.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <assert.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    LPGROUP_USERS_INFO_0 pBuf = NULL;    DWORD dwLevel = 0;    DWORD dwPrefMaxLen = -1;    DWORD dwEntriesRead = 0;    DWORD dwTotalEntries = 0;    NET_API_STATUS nStatus;    if (argc != 3)    {       fwprintf(stderr, L"Usage: %s \\ServerName UserName\n", argv[0]);       exit(1);    }    //    // Call the NetUserGetGroups function, specifying level 0.    //    nStatus = NetUserGetGroups(argv[1],                               argv[2],                               dwLevel,                               (LPBYTE*)&pBuf,                               dwPrefMaxLen,                               &dwEntriesRead,                               &dwTotalEntries);    //    // If the call succeeds,    //    if (nStatus == NERR_Success)    {       LPGROUP_USERS_INFO_0 pTmpBuf;       DWORD i;       DWORD dwTotalCount = 0;       if ((pTmpBuf = pBuf) != NULL)       {          fprintf(stderr, "\nGlobal group(s):\n");          //          // Loop through the entries;           //  print the name of the global groups           //  to which the user belongs.          //          for (i = 0; i < dwEntriesRead; i++)          {             assert(pTmpBuf != NULL);             if (pTmpBuf == NULL)             {                fprintf(stderr, "An access violation has occurred\n");                break;             }             wprintf(L"\t %s\n", pTmpBuf->grui0_name);             pTmpBuf++;             dwTotalCount++;          }       }       //       // If all available entries were       //  not enumerated, print the number actually        //  enumerated and the total number available.       //       if (dwEntriesRead < dwTotalEntries)          fprintf(stderr, "\nTotal entries: %d", dwTotalEntries);       //       // Otherwise, just print the total.       //       printf("\nEntries enumerated: %d\n", dwTotalCount);    }    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    //    // Free the allocated buffer.    //    if (pBuf != NULL)       NetApiBufferFree(pBuf);    return 0; } 

Adding a User Account

The following examples illustrate migrating code to add user accounts from UNIX to Windows.

UNIX Example: Adding a User Account

This example uses the getpwnam and getpwuid functions to verify that a user account and uid does not already exist before adding a new user account with the putpwent function. This program assumes that a user home directory with the same name has already been created under /home, and does not verify that this directory exists.

 #define _XOPEN_SOURCE #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <pwd.h> int main(int argc, char *argv[]) {     struct passwd pswd;     struct passwd *ptr_pswd;     char pw_name[20];     char pw_passwd[30];     char pw_dir[26];     char pw_shell[15];     int uid;     pswd.pw_name = pw_name;     pswd.pw_passwd = pw_passwd;     pswd.pw_dir = pw_dir;     pswd.pw_shell = pw_shell;     if (argc != 5)     {        printf("Usage: %s UserName Password UID GID\n", argv[0]);        exit(1);     } // Call the getpwnam function to check if user exists.     if(ptr_pswd = getpwnam (argv[1])) {         printf("user already exists\n");         exit(1);     } // Call the getpwuid function to check if User ID exists     if(ptr_pswd = getpwuid (uid=(uid_t) atoi(argv[3]))) {         printf("user ID already exists\n");         exit(1);     }     ptr_pswd = &pswd;     strcpy (ptr_pswd->pw_name, argv[1]);     printf ("Name: %s\n", ptr_pswd->pw_name);     strcpy (ptr_pswd->pw_passwd, crypt(argv[2],"az"));     ptr_pswd->pw_uid = uid;     printf ("uid: %d\n", ptr_pswd->pw_uid);     ptr_pswd->pw_gid = (gid_t) atoi(argv[4]);     printf ("gid: %d\n", ptr_pswd->pw_gid);     strcpy (ptr_pswd->pw_dir, "/home/");     strcat (ptr_pswd->pw_dir, argv[1]);     printf ("Home Dir: %s\n", ptr_pswd->pw_dir);     strcpy (ptr_pswd->pw_shell, "/bin/bash");     printf ("Shell: %s\n", ptr_pswd->pw_shell); // Call the putpwent function     putpwent(ptr_pswd, fopen ("/etc/passwd", "a+"));     exit(0); } 

Win32 Example: Adding a User Account

This example uses NetUserAdd() function to add a user account and assignsa password and privilege level.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    USER_INFO_1 ui;    DWORD dwLevel = 1;    DWORD dwError = 0;    NET_API_STATUS nStatus;    if (argc != 3)    {       fwprintf(stderr, L"Usage: %s \\ServerName UserName\n", argv[0]);       exit(1);    }    //    // Set up the USER_INFO_1 structure.    //  USER_PRIV_USER: name identifies a user,     //    rather than an administrator or a guest.    //  UF_SCRIPT: required for LAN Manager 2.0 and    //    Windows NT and later.    //    ui.usri1_name = argv[2];    ui.usri1_password = argv[2];    ui.usri1_priv = USER_PRIV_USER;    ui.usri1_home_dir = NULL;    ui.usri1_comment = NULL;    ui.usri1_flags = UF_SCRIPT;    ui.usri1_script_path = NULL;    //    // Call the NetUserAdd function, specifying level 1.    //    nStatus = NetUserAdd(argv[1],                         dwLevel,                         (LPBYTE)&ui,                         &dwError);    //    // If the call succeeds, inform the user.    //    if (nStatus == NERR_Success)       fwprintf(stderr, L"User %s has been successfully added on %s\n",                argv[2], argv[1]);    //    // Otherwise, print the system error.    //    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    return 0; } 

Changing a User s Password

The following examples illustrate migrating code to change a user s password from UNIX to Windows.

UNIX Example: Changing a User s Password

This example uses the getpwnam function to verify that the user account exists before creating a new /etc/passwd file (named /etc/passwdx) with the entered password using a combination of the fgetpwent and fprintf functions. This program assumes that the super user will be using this program, and will manually copy /etc/passwdx to /etc/passwd after verifying proper update to the user entries.

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <pwd.h> int main(int argc, char *argv[]) {     struct passwd pswd;     struct passwd *ptr_pswd;     FILE *stream_in, *stream_out;     if (argc != 3)     {        printf("Usage: %s UserName Password\n", argv[0]);        exit(1);     } // Call the getpwnam function to check if user exists.     if(!(ptr_pswd = getpwnam (argv[1]))) {         printf("user does not exist\n");         exit(1);     }     ptr_pswd = &pswd; // Scan /etc/passwd file, create /etc/passwdx, with updated user entry     stream_in = fopen ("/etc/passwd", "r");     stream_out = fopen ("/etc/passwdx", "w");     while(ptr_pswd = fgetpwent(stream_in)) {         if(strcmp(ptr_pswd->pw_name, argv[1]) == 0)             strcpy (ptr_pswd->pw_passwd, crypt(argv[2],"az"));             fprintf(stream_out, "%s:%s:%d:%d:%s:%s:%s\n", ptr_pswd->pw_name,\                     ptr_pswd->pw_passwd, ptr_pswd->pw_uid, ptr_pswd->pw_gid,\                     ptr_pswd->pw_gecos, ptr_pswd->pw_dir, ptr_pswd->pw_shell);         printf("Next Name: %s\n", ptr_pswd->pw_name);     }     fclose (stream_in);     fclose (stream_out);     exit(0); } 

Win32 Example: Changing a User s Password

This example uses the NetUserChangePassword() function to change a user s password for a specified network server or domain.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    DWORD dwError = 0;    NET_API_STATUS nStatus;    //    // All parameters are required.    //    if (argc != 5)    {       fwprintf(stderr, L"Usage: %s \\ServerName UserName OldPassword  NewPassword\n", argv[0]);       exit(1);    }    //    // Call the NetUserChangePassword function.    //    nStatus = NetUserChangePassword(argv[1], argv[2], argv[3], argv[4]);    //    // If the call succeeds, inform the user.    //    if (nStatus == NERR_Success)       fwprintf(stderr, L"User password has been changed successfully\n");    //    // Otherwise, print the system error.    //    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    return 0; } 

Removing a User Account

The following examples illustrate migrating code to remove user accounts from UNIX to Windows.

UNIX Example: Removing a User Account

This example uses the getpwnam function to verify that the user account exists before creating a new /etc/passwd file (named /etc/passwdx). It does so with the specified user account removed, using a combination of the fgetpwent and fprintf functions. This program assumes that the super user will be using this program, and will manually copy /etc/passwdx to /etc/passwd after verifying proper update to the user entries.

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <pwd.h> int main(int argc, char *argv[]) {     struct passwd pswd;     struct passwd *ptr_pswd;     FILE *stream_in, *stream_out;     if (argc != 2)     {        printf("Usage: %s UserName\n", argv[0]);        exit(1);     } // Call the getpwnam function to check if user exists.     if(!(ptr_pswd = getpwnam (argv[1]))) {         printf("user does not exist\n");         exit(1);     }     ptr_pswd = &pswd; // Scan /etc/passwd file, create /etc/passwdx, with updated user entry     stream_in = fopen ("/etc/passwd", "r");     stream_out = fopen ("/etc/passwdx", "w");     while(ptr_pswd = fgetpwent(stream_in)) {         if(strcmp(ptr_pswd->pw_name, argv[1]) != 0)             fprintf(stream_out, "%s:%s:%d:%d:%s:%s:%s\n", ptr_pswd->pw_name,\                     ptr_pswd->pw_passwd, ptr_pswd->pw_uid, ptr_pswd->pw_gid,\                     ptr_pswd->pw_gecos, ptr_pswd->pw_dir, ptr_pswd->pw_shell);         printf("Next Name: %s\n", ptr_pswd->pw_name);     }     fclose (stream_in);     fclose (stream_out);     exit(0); } 

Win32 Example: Removing a User Account

This example uses the NetUserDel() function to delete a user account from a server.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    DWORD dwError = 0;    NET_API_STATUS nStatus;    //    // All parameters are required.    //    if (argc != 3)    {       fwprintf(stderr, L"Usage: %s \\ServerName UserName\n", argv[0]);       exit(1);    }    //    // Call the NetUserDel function to delete the share.    //    nStatus = NetUserDel(argv[1], argv[2]);    //    // Display the result of the call.    //    if (nStatus == NERR_Success)       fwprintf(stderr, L"User %s has been successfully deleted on %s\n",                argv[2], argv[1]);    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    return 0; } 

Getting User Information About All Users

The following examples illustrate migrating code to get user information from UNIX to Windows.

UNIX Example: Getting User Information About All Users

This example uses the getpwent function to provide information about all available user accounts.

 #include <stdio.h> #include <unistd.h> #include <pwd.h> int main() {     struct passwd pswd;     struct passwd *ptr_pswd; // Scan /etc/passwd file     while(ptr_pswd = getpwent())         printf("Account Name: %s\n", ptr_pswd->pw_name);     exit(0); } 

Win32 Example: Getting User Information About All Users

This example uses the NetUserEnum() function to provide information about all the users on a server.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <assert.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    LPUSER_INFO_0 pBuf = NULL;    LPUSER_INFO_0 pTmpBuf;    DWORD dwLevel = 0;    DWORD dwPrefMaxLen = -1;    DWORD dwEntriesRead = 0;    DWORD dwTotalEntries = 0;    DWORD dwResumeHandle = 0;    DWORD i;    DWORD dwTotalCount = 0;    NET_API_STATUS nStatus;    LPTSTR pszServerName = NULL;    if (argc > 2)    {       fwprintf(stderr, L"Usage: %s [\\ServerName]\n", argv[0]);       exit(1);    }    // The server is not the default local computer.    //    if (argc == 2)       pszServerName = argv[1];    wprintf(L"\nUser account on %s: \n", pszServerName);    //    // Call the NetUserEnum function, specifying level 0;     //   enumerate global user account types only.    //    do // begin do    {       nStatus = NetUserEnum(pszServerName,                             dwLevel,                             FILTER_NORMAL_ACCOUNT, // global users                             (LPBYTE*)&pBuf,                             dwPrefMaxLen,                             &dwEntriesRead,                             &dwTotalEntries,                             &dwResumeHandle);       //       // If the call succeeds,       //       if ((nStatus == NERR_Success)  (nStatus == ERROR_MORE_DATA))       {          if ((pTmpBuf = pBuf) != NULL)          {             //             // Loop through the entries.             //             for (i = 0; (i < dwEntriesRead); i++)             {                assert(pTmpBuf != NULL);                if (pTmpBuf == NULL)                {                   fprintf(stderr, "An access violation has occurred\n");                   break;                }                //                //  Print the name of the user account.                //                wprintf(L"\t %s\n", pTmpBuf->usri0_name);                pTmpBuf++;                dwTotalCount++;             }          }       }       //       // Otherwise, print the system error.       //       else          fprintf(stderr, "A system error has occurred: %d\n", nStatus);       //       // Free the allocated buffer.       //       if (pBuf != NULL)       {          NetApiBufferFree(pBuf);          pBuf = NULL;       }    }    // Continue to call NetUserEnum while     //  there are more entries.     //     while (nStatus == ERROR_MORE_DATA); // end do    //    // Check again for allocated memory.    //    if (pBuf != NULL)       NetApiBufferFree(pBuf);    //    // Print the final count of users enumerated.    //    fprintf(stderr, "\nTotal of %d entries enumerated\n", dwTotalCount);    return 0; } 

Getting Information About a Specific User

The following examples illustrate migrating code from UNIX to Windows to get information about a specific user account.

UNIX Example: Getting Information About a Specific User

This example uses the getpwnam function to obtain the information and output the account information of a specified user.

 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <pwd.h> int main(int argc, char *argv[]) {     struct passwd *ptr_pswd;     int uid;     if (argc != 2)     {        printf("Usage: %s UserName\n", argv[0]);        exit(1);     } // Call the getpwnam function to check if user exists.     if(!(ptr_pswd = getpwnam (argv[1]))) {         printf("user does not exist\n");         exit(1);     }     printf ("Name: %s\n", ptr_pswd->pw_name);     printf ("uid: %d\n", ptr_pswd->pw_uid);     printf ("gid: %d\n", ptr_pswd->pw_gid);     printf ("Home Dir: %s\n", ptr_pswd->pw_dir);     printf ("Shell: %s\n", ptr_pswd->pw_shell);     exit(0); } 

Win32 Example: Getting Information About a Specific User

This example uses NetUserGetInfo() function to retrieve information about a particular user account on a server. This function returns specific information in USER INFO structure based on different levels. For more details, see the Platform SDK documentation.

 #ifndef UNICODE #define UNICODE #endif #include <stdio.h> #include <windows.h>  #include <lm.h> int wmain(int argc, wchar_t *argv[]) {    DWORD dwLevel = 10;    LPUSER_INFO_10 pBuf = NULL;    NET_API_STATUS nStatus;    if (argc != 3)    {       fwprintf(stderr, L"Usage: %s \\ServerName UserName\n", argv[0]);       exit(1);    }    //    // Call the NetUserGetInfo function; specify level 10.    //    nStatus = NetUserGetInfo(argv[1],                             argv[2],                             dwLevel,                             (LPBYTE *)&pBuf);    //    // If the call succeeds, print the user information.    //    if (nStatus == NERR_Success)    {     if (pBuf != NULL)       {          wprintf(L"\n\tAccount:      %s\n", pBuf->usri10_name);          wprintf(L"\tComment:      %s\n", pBuf->usri10_comment);          wprintf(L"\tUser comment: %s\n", pBuf->usri10_usr_comment);          wprintf(L"\tFull name:    %s\n", pBuf->usri10_full_name);       }    }    // Otherwise, print the system error.    //    else       fprintf(stderr, "A system error has occurred: %d\n", nStatus);    //    // Free the allocated memory.    //    if (pBuf != NULL)       NetApiBufferFree(pBuf);    return 0; } 

Retrieving the Current User s User Name

The following examples illustrate migrating code from UNIX to Windows to retrieve the current user s user name.

UNIX Example: Retrieving the Current User s User Name

This example uses the getlogin() function to retrieve the user name of the user currently logged onto the system.

 #include <stdio.h> #include <unistd.h> main() { // Get and display the user name.     printf("User name: %s\n", getlogin()); } 

Win32 Example: Retrieving the Current User s User Name

This example uses GetUserName() function to retrieve the user name of the current thread. This is the name of the user currently logged on to the system.The GetUserNameEx() function can be used to retrieve the user name in a specified format.

 #include <windows.h> #include <stdio.h> #include <lmcons.h> void main() {     LPTSTR lpszSystemInfo;          // pointer to system information string      DWORD cchBuff = 256;            // size of user name      TCHAR tchBuffer[UNLEN + 1];     // buffer for expanded string        lpszSystemInfo = tchBuffer;        // Get and display the user name.      GetUserName(lpszSystemInfo, &cchBuff);      printf("User name: %s\n", lpszSystemInfo); } 

Security Functions

Windows security enables you to control the ability of a process to access securable objects or to perform various system administration tasks . Application developers use access control to control access to securable objects such as files, registry keys, and directory service objects.

Table 9.13 shows the two basic components of the Windows access-control model.

Table 9.13: Windows Access-Control Model Components

Access-control component

Description

Access tokens

Access tokens contain information about a logged-on user.

Security descriptors

Security descriptors contain the security information that protects a securable object.

When a user logs on to a Windows system, the system authenticates the user s account name and password. If the logon is successful, the system creates an access token. Every process executed on behalf of this user will have a copy of this access token. The access token contains security identifiers (SIDs) that identify the user s account and any group accounts to which the user belongs. The token also contains a list of the privileges held by the user or the user s groups. The system uses this token to identify the associated user when a process tries to access a securable object or perform a system administration task that requires privileges.

An access-control list (ACL) is a list of access-control entries (ACEs). Each ACE inan ACL identifies a trustee and specifies the access rights allowed, denied , or audited for that trustee. The security descriptor for a securable object can contain two ACLs: a DACL and a SACL.

A DACL (discretionary access-control list) identifies the trustees that are allowed or denied access to a securable object. When a process tries to access a securable object, the system checks the ACEs in the object s DACL to determine whether to grant access to it. If the object does not have a DACL, the system grants full access to everyone.If the object s DACL has no ACEs, the system denies all attempts to access the object because the DACL does not allow any access rights. The system checks the ACEs in sequence until it finds one or more ACEs that allow all the requested access rights, or until any of the requested access rights are denied.

A system access-control list (SACL) enables administrators to log attempts to access a secured object. Each ACE specifies the types of access attempts by a specified trustee that cause the system to generate a record in the security event log. An ACE in a SACL can generate audit records when an access attempt fails, when it succeeds, or both. In future releases, a SACL can also raise an alarm when an unauthorized user attempts to gain access to an object.

UNIX Example: Using Security Functions

This example and the following Win32 example illustrate migrating code from UNIX to Windows that uses basic security functions.

 #include <stdio.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <err.h> #include <pwd.h> int main() {     struct passwd pswd;     struct stat stat_info;     uid_t uid;     int rtn;     struct passwd * ptr_pswd = &pswd; // Get the owner UID of the file. // and Check error code.     if (stat ("myfile.txt", &stat_info) == -1)         err(1, NULL);     uid = stat_info.st_uid; // Lookup Account UID to get the owners name. // and Check error code.     if(ptr_pswd = getpwuid (uid)) // Print the account name.         printf("owner: %s\n", ptr_pswd->pw_name);     else         err(1, NULL); } 

Win32 Example: Using Security Functions

This example uses the GetSecurityInfo() and LookupAccountSid() functionsto find and print the name of the owner of a file. The file exists in the current working directory on the local server.

 #include <stdio.h> #include <windows.h> #include <tchar.h> #include "accctrl.h" #include "aclapi.h" int main(int argc, char **argv) {     DWORD dwRtnCode = 0;     PSID pSidOwner;     BOOL bRtnBool = TRUE;     LPTSTR AcctName, DomainName;     DWORD dwAcctName = 1, dwDomainName = 1;     SID_NAME_USE eUse = SidTypeUnknown;     HANDLE hFile;     PSECURITY_DESCRIPTOR pSD;     LPVOID lpMsgBuf;     // Get the handle of the file object.     hFile = CreateFile("myfile.txt",                       GENERIC_READ,                       FILE_SHARE_READ,                       NULL,                       OPEN_EXISTING,                       FILE_ATTRIBUTE_NORMAL,                       NULL);     // Check GetLastError for CreateFile error code.     if (hFile == INVALID_HANDLE_VALUE) {         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER               FORMAT_MESSAGE_FROM_SYSTEM               FORMAT_MESSAGE_IGNORE_INSERTS,             NULL,             GetLastError(),             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language             (LPTSTR) &lpMsgBuf,             0,             NULL);         _tprintf(TEXT("Error message:%s\n"), lpMsgBuf);         LocalFree(lpMsgBuf);                return -1;     }     // Allocate memory for the SID structure.     pSidOwner = (PSID)GlobalAlloc(GMEM_FIXED,               sizeof(PSID));     // Allocate memory for the security descriptor structure.     pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GMEM_FIXED,               sizeof(PSECURITY_DESCRIPTOR));     // Get the owner SID of the file.     dwRtnCode = GetSecurityInfo(hFile,                       SE_FILE_OBJECT,                       OWNER_SECURITY_INFORMATION,                       &pSidOwner,                       NULL,                       NULL,                       NULL,                       &pSD);     // Check GetLastError for GetSecurityInfo error condition.     if (dwRtnCode != ERROR_SUCCESS) {               DWORD dwErrorCode = 0;               dwErrorCode = GetLastError();               _tprintf(TEXT("GetSecurityInfo error = %d\n"), dwErrorCode);               return -1;     }     // First call to LookupAccountSid to get the buffer sizes.     DomainName = NULL;     AcctName = NULL;     bRtnBool = LookupAccountSid(NULL,           // local computer                       pSidOwner,                       AcctName,                       (LPDWORD)&dwAcctName,                       DomainName,                       (LPDWORD)&dwDomainName,                       &eUse);     // Reallocate memory for the buffers.     AcctName = (char *)GlobalAlloc(GMEM_FIXED,               dwAcctName);     // Check GetLastError for GlobalAlloc error condition.     if (AcctName == NULL) {               DWORD dwErrorCode = 0;               dwErrorCode = GetLastError();               _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);               return -1;     }     DomainName = (char *)GlobalAlloc(GMEM_FIXED,            dwDomainName);     // Check GetLastError for GlobalAlloc error condition.     if (DomainName == NULL) {           DWORD dwErrorCode = 0;           dwErrorCode = GetLastError();           _tprintf(TEXT("GlobalAlloc error = %d\n"), dwErrorCode);           return -1;     }     // Second call to LookupAccountSid to get the account name.     bRtnBool = LookupAccountSid(NULL,                          // name of local or remote computer           pSidOwner,                     // security identifier           AcctName,                      // account name buffer           (LPDWORD)&dwAcctName,          // size of account name buffer            DomainName,                    // domain name           (LPDWORD)&dwDomainName,        // size of domain name buffer           &eUse);                        // SID type     // Check GetLastError for LookupAccountSid error condition.     if (bRtnBool == FALSE) {           DWORD dwErrorCode = 0;           dwErrorCode = GetLastError();           if (dwErrorCode == ERROR_NONE_MAPPED)               _tprintf(TEXT("Account owner not found for specified SID.\n"));           else                _tprintf(TEXT("Error in LookupAccountSid.\n"));           return -1;     } else if (bRtnBool == TRUE)      // Print the account name.     _tprintf(TEXT("Account owner = %s\n"), AcctName);     return 0; } 



UNIX Application Migration Guide
Unix Application Migration Guide (Patterns & Practices)
ISBN: 0735618380
EAN: 2147483647
Year: 2003
Pages: 134

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net