I want to retrieve motherboard ID from a C++ program on Linux (Ubuntu) without root privileges. I know that dmidecode can do this, but it requires root privileges, so it is not suitable for my needs. Does anyone know of non-root alternatives? Source code will be much appreciated.
You don't have to be root to get the information, but you do need to have root first give you permission. Obviously root is allowed to secure access to their machine, and this includes access to hardware identity information.
root controls what the software on their machine can do, your software does not restrict what root can do. (Linux Corollary to The #1 Law of Software Licensing)
If root chooses to install your hardware id collector, it's relatively straightforward to make that data available to non-root users (but it's also relatively easy for root to modify your id collector to lie).
$ lshal | grep 'system\.hardware\.serial'
system.hardware.serial = '<serial-number>' (string)
Works as non-root user on FC11.
lshw should get the serial for you. It will tell you it should be run as superuser but will run anyway. (tested on ubuntu)
sudo dmidecode --type baseboard
I think you need to be root
opening up /proc/pci will give you alot of information chipset etc, not sure if /proc/ has a specific directory for motherboard or BIOS info, have a look ls /proc ?
Other than that you could look at calling the dmidecode commandline tool from your application and capturing its output. If thats not good enough, perhaps even look at the source code of dmidecode to see how it works?
Andrew
Related
I need to write a function that generates an id that is unique for a given machine running a Windows OS.
Currently, I'm using WMI to query various hardware parameters and concatenate them together and hash them to derive the unique id. My question is, what are the suggested parameters I should use?
Currently, I'm using a combination of bios\cpu\disk data to generate the unique id. And am using the first result if multiple results are there for each metric.
However, I ran into an issue where a machine that dual boots into 2 different Windows OS generates different site codes on each OS, which should ideally not happen.
For reference, these are the metrics I'm currently using:
Win32_Processor:UniqueID,ProcessorID,Name,Manufacturer,MaxClockSpeed
Win32_BIOS:Manufacturer
Win32_BIOS:SMBIOSBIOSVersion,IdentificationCode,SerialNumber,ReleaseDate,Version
Win32_DiskDrive:Model, Manufacturer, Signature, TotalHeads
Win32_BaseBoard:Model, Manufacturer, Name, SerialNumber
Win32_VideoController:DriverVersion, Name
I had the same problem and after a little research I decided the best would be to read MachineGuid in registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography, as #Agnus suggested. It is generated during OS installation and won't change unless you make another fresh OS install. Depending on the OS version it may contain the network adapter MAC address embedded (plus some other numbers, including random), or a pseudorandom number, the later for newer OS versions (after XP SP2, I believe, but not sure). If it's a pseudorandom theoretically it can be forged - if two machines have the same initial state, including real time clock. In practice, this will be rare, but be aware if you expect it to be a base for security that can be attacked by hardcore hackers.
Of course a registry entry can also be easily changed by anyone to forge a machine GUID, but what I found is that this would disrupt normal operation of so many components of Windows that in most cases no regular user would do it (again, watch out for hardcore hackers).
With our licensing tool we consider the following components
MAC Address
CPU (Not the serial number, but the actual CPU profile like stepping and model)
System Drive Serial Number (Not Volume Label)
Memory
CD-ROM model & vendor
Video Card model & vendor
IDE Controller
SCSI Controller
However, rather than just hashing the components and creating a pass/fail system, we create a comparable fingerprint that can be used to determine how different two machine profiles are. If the difference rating is above a specified tolerance then ask the user to activate again.
We've found over the last 8 years in use with hundreds of thousands of end-user installs that this combination works well to provide a reliably unique machine id - even for virtual machines and cloned OS installs.
Parse the SMBIOS yourself and hash it to an arbitrary length. See the PDF specification for all SMBIOS structures available.
To query the SMBIOS info from Windows you could use EnumSystemFirmwareEntries, EnumSystemFirmwareTables and GetSystemFirmwareTable.
IIRC, the "unique id" from the CPUID instruction is deprecated from P3 and newer.
What about just using the UniqueID of the processor?
I hate to be the guy who says, "you're just doing it wrong" (I always hate that guy ;) but...
Does it have to be repeatably generated for the unique machine? Could you just assign the identifier or do a public/private key? Maybe if you could generate and store the value, you could access it from both OS installs on the same disk?
You've probably explored these options and they doesn't work for you, but if not, it's something to consider.
If it's not a matter of user trust, you could just use MAC addresses.
You should look into using the MAC address on the network card (if it exists). Those are usually unique but can be fabricated. I've used software that generates its license file based on your network adapter MAC address, so it's considered a fairly reliable way to distinguish between computers.
For one of my applications, I either use the computer name if it is non-domain computer, or the domain machine account SID for domain computers. Mark Russinovich talks about it in this blog post, Machine SID:
The final case where SID duplication would be an issue is if a distributed application used machine SIDs to uniquely identify computers. No Microsoft software does so and using the machine SID in that way doesn’t work just for the fact that all DC’s have the same machine SID. Software that relies on unique computer identities either uses computer names or computer Domain SIDs (the SID of the computer accounts in the Domain).
You can access the domain machine account SID via LDAP or System.DirectoryServices.
In my program I first check for Terminal Server and use the WTSClientHardwareId. Else the MAC address of the local PC should be adequate.
If you really want to use the list of properties you provided leave out things like Name and DriverVersion, Clockspeed, etc. since it's possibly OS dependent. Try outputting the same info on both operating systems and leave out that which differs between.
There is a library available for getting hardware specific informations: Hardware serial number extractor (CPU, RAM, HDD, BIOS)
Maybe cheating a little, but the MAC Address of a machines Ethernet adapter rarely changes without the motherboard changing these days.
Can you pull some kind of manufacturer serial number or service tag?
Our shop is a Dell shop, so we use the service tag which is unique to each machine to identify them. I know it can be queried from the BIOS, at least in Linux, but I don't know offhand how to do it in Windows.
I had an additional constraint, I was using .net express so I couldn't use the standard hardware query mechanism. So I decided to use power shell to do the query. The full code looks like this:
Private Function GetUUID() As String
Dim GetDiskUUID As String = "get-wmiobject Win32_ComputerSystemProduct | Select-Object -ExpandProperty UUID"
Dim X As String = ""
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("powershell.exe", GetDiskUUID)
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardInput = True
oStartInfo.RedirectStandardOutput = True
oStartInfo.CreateNoWindow = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
oProcess.WaitForExit()
X = oProcess.StandardOutput.ReadToEnd
Return X.Trim()
End Function
Look up CPUID for one option. There might be some issues with multi-CPU systems.
Try this one, it gives a unique hard disk ID: Port of DiskId32 for Delphi 7-2010.
Is there a command that can list all the Permissions of a file/folder?
I need to be able to list permission from Novell Server as well as Windows Server for integrity checking.
I have searched through and found "icacls" but I believe it can only change permission.
Please advise
For the windows side (it's been almost 20 years since I played with Novell)
icacls can definitely dump permissions, just run icacls /? for the usage information.
If you find that is difficult to read, you might prefer to use dumpsec instead http://www.systemtools.com/somarsoft/index.html
I’m using QDir::drives() to get the list of drives. It works great on Windows, but on Linux and Mac it only returns a single item “/”, i. e. root. It is expected behavior, but how can I get a list of drives on Mac and Linux?
Non-Qt, native API solutions are also welcome.
Clarification on "drive" definition: I'd like to get a list of mount points that are visble as "drives" in Finder or Linux built-in file manager.
As far as the filesystem is concerned, there is no concept of drives in Unix/Linux (I can't vouch for MacOSX but I'd say it's the same). The closest thing would probably be mount points, but a normal application shouldn't bother about them since all is already available under the filesystem root / (hence the behaviour of QDir::drives() that you observe).
If you really want to see which mount points are in use, you could parse the output of the mount command (without any arguments) or, at least on Linux, the contents of the /etc/mtab file. Beware though, mount points can get pretty hairy real quick (loop devices, FUSE filesystems, network shares, ...) so, again, I wouldn't recommend making use of them unless your application is designed to administer them.
Keep in mind that on Unix-y OSes, mount points are normally a matter for system administrators, not end-users, unless we're speaking of removable media or transient network shares.
Edit: Following your clarifications in the comments, on Linux you should use getmntent or getmntent_r to parse the contents of the /etc/mtab file and thus get a list of all mount points and the corresponding devices.
The trick after that is to determine which ones you want to display (removable? network share?). I know that /sys/block/... can help with that, but I don't know all the details so you'll have to dig a bit more.
For example, to check whether /dev/sdd1 (a USB key) mounted on /media/usb0/ is a removable device, you could do (note how I use the device name sdd, not the partition name sdd1):
$ cat /sys/block/sdd/removable
1
As opposed to my main hard drive:
$ cat /sys/block/sda/removable
0
Hope this puts you on the right track.
For OS X, the Disk Arbitration framework can be used to list and monitor drives and mount points
Scraping the output of mount shell command is certainly one option on either platform - although, what is your definition of a drive here? Physical media, removable drivers, network volumes? You'll need to do a lot of filtering.
On MacOSX, the mount point for removable media, network volumes, and secondary hard-drives is always under /Volumes/, so simply enumerating items in this directory will do the trick if your definition of a drive is broad. This ought to be fairly safe as they're all automounted .
On Linux, there are a variety of locations depending on the particular distro in use. /mnt/ is the traditional, but there are others.
In linux, the way to get information about drives currently mounted is to parse the mtab file. glibc provides a macro _PATH_MNTTAB to locate this file. See http://www.gnu.org/software/libc/manual/html_node/Mount-Information.html#Mount-Information
If you know the format of the drive/drives in question, you can use the df command to output the list of drives from the console or programatically as a system command. For example, to find all the ext4 drives:
df -t ext4
You can simply add additional formats onto the same command if you are interested in more than one type:
df -t ext4 -t tmpfs
This is going to return to you the physical location of the drive, the amount of memory it has, the amount of memory used, the amount of memory free, the use% and where it is mounted on the filesystem.
df will show you all of the drives mounted on the system, but some are going to be things that aren't really what you are looking for like temporary file systems, etc.
Not sure if this will work on OSX or not, but it does work on my Ubuntu 12.04 distribution.
Another way is to check for "Volumes"
df -H | grep "/Volumes"
I know that this is old, but it failed to mention getfsstat which I ended up using in macos. You can get a list of mounts (which will include most disks) using getfsstat. See man 2 getfsstat for further information.
I need to programmely switch the current user to another,then the followed code should be executed in the environment(such as path,authority..) of another user.
I've find the 'chroot()','setuid()' may be associated with my case, but these functions need the root authority, I don't have root authority, but I have the password of the second user. what should I do?
I have tried shell "su - " can switch current user, can this command help me in my C++ code?
Don't laugh at me if my question is very stupid, I'm a true freshman on linux. :)
Thanks!
when clients connect to the server,
the server transfer the data what they
need,but the precondition is the
correct username and password.
If your primary requirement is to authenticate, then try man pam. There are also some libraries allowing to auth over LDAP. Unfortunately I have no personal experience implementing neither.
Otherwise, recreating complete user environment is unreliable and error prone. Imaging a typo or endless loop but in user's ~/.profile.
I haven't done that for some time, but I would also have tried to dig in direction of "su", figuring out user shell (from /etc/passwd) and trying to exec() it as if it was a login shell (with "-"). But after that you would need somehow to communicate a command for execution to it and that's a problem: shells run differently in batch more and in interactive mode. As a possible hack, expect (man expect) comes to mind, but it is still IMO too unreliable.
I have in past used ssh under expect (to input the password), but it was breaking on customized user profiles every other time. With expect, to send a command, one has to recognize somehow that shell has finished initialization (execution of profile and rc files). But since many people customize the shell prompt and their profile/rc files print extra info, it was quite often that expect was recognizing shell prompt too soon.
BTW, depending on number of users, one can try a setup where users manually start the server under their own account. The server would have access only to the information which is only accessible to the user.
You can use the system function to execute shell commands on the operating system.
You could take a look at the source code of the login command, or you could try using the exec()-family functions to call on login.
EDIT: Seems like you will need root access in any case.
Is setuid what you're looking for?
I think the key point here is that you can't change the user of the running process (easily). All the programs like 'su' are effectively starting a new process as the specified user.
Therefore, in your design I would recommend seperating off the functionality that needs to be done into a different executable and then investigate using execve() to start it.
How can I find the user's home directory in a cross platform manner in C++? i.e. /home/user in Linux, C:\Users\user\ on Windows Vista, C:\Documents And Settings\user\ on Windows XP, and whatever it is that Macs use. (I think it's /User/user)
Basically, what I'm looking for is a C++ way of doing this (example in python)
os.path.expanduser("~")
I don't think it's possible to completely hide the Windows/Unix divide with this one (unless, maybe, Boost has something).
The most portable way would have to be getenv("HOME") on Unix and concatenating the results of getenv("HOMEDRIVE") and getenv("HOMEPATH") on Windows.
This is possible, and the best way to find it is to study the source code of os.path.expanduser("~"), it is really easy to replicate the same functionality in C.
You'll have to add some #ifdef directives to cover different systems.
Here are the rules that will provide you the HOME directory
Windows: env USERPROFILE or if this fails, concatenate HOMEDRIVE+HOMEPATH
Linux, Unix and OS X: env HOME or if this fails, use getpwuid() (example code)
Important remark: many people are assuming that HOME environment variable is always available on Unix but this is not true, one good example would be OS X.
On OS X when you run an application from GUI (not console) this will not have this variable set so you need to use the getpwuid().
The home directory isn't really a cross-platform concept. Your suggestion of the root of the profile directory (%USERPROFILE%) is a fair analogy, but depending what you want to do once you have the directory, you might want one of the Application Data directories, or the user's My Documents. On UNIX, you might create a hidden ".myapp" in the home directory to keep your files in, but that's not right on Windows.
Your best bet is to write specific code for each platform, to get at the directory you want in each case. Depending how correct you want to be, it might be enough to use env vars: HOME on UNIX, USERPROFILE or APPDATA (depending what you need) on Windows.
On UNIX at least (any Windows folks care to comment?), it's usually good practice to use the HOME environment variable if it's set, even if it disagrees with the directory specific in the password file. Then, on the odd occasion when users want all apps to read their data from a different directory, it will still work.